fix p2p conversation avatars

This commit is contained in:
richjohnrambo
2026-10-14 16:09:38 +08:00
parent 8a26a4ccf9
commit 361e23b9ec
3 changed files with 47 additions and 2 deletions
+3 -2
View File
@@ -6,6 +6,7 @@ import { Link, useLocation, useNavigate, useParams } from 'react-router-dom';
import { Avatar } from '@/app/Avatar';
import { Icon } from '@/app/Icon';
import { CreateGroupModal } from '@/features/groups/CreateGroupModal';
import { friendAvatarLookup } from '@/features/messages/chat-list';
import { fetchAllPages } from '@/lib/api/client';
import { getFriends } from '@/lib/api/friends';
import { getGroups } from '@/lib/api/groups';
@@ -74,7 +75,7 @@ export function ChatListColumn() {
// to carry the REST-only `avatar_file_id` this app uploads avatars through -- shares ContactsListColumn's
// exact `['friends']` query key, so this is a cache read whenever that page has already been visited.
const friendsQuery = useQuery({ queryKey: ['friends'], queryFn: () => fetchAllPages((cursor) => getFriends('', cursor)) });
const avatarByUserId = new Map(friendsQuery.data?.map((f) => [f.user_id, f.avatar_file_id]));
const avatarByPeer = friendAvatarLookup(friendsQuery.data);
const [query, setQuery] = useState('');
const [creatingGroup, setCreatingGroup] = useState(false);
const sorted = [...contacts].sort((a, b) => {
@@ -158,7 +159,7 @@ export function ChatListColumn() {
const memberCount = isGroup ? memberCountByTopic.get(contact.topic) : undefined;
const muted = !!contact.private?.mute_notifications;
const avatarFileId =
contact.topic === 'slf' ? meQuery.data?.profile.avatar_file_id : isGroup ? avatarByGroupTopic.get(contact.topic) : avatarByUserId.get(contact.topic);
contact.topic === 'slf' ? meQuery.data?.profile.avatar_file_id : isGroup ? avatarByGroupTopic.get(contact.topic) : avatarByPeer.get(contact.topic);
return (
<Link
key={contact.topic}
+20
View File
@@ -0,0 +1,20 @@
export interface FriendAvatarSource {
user_id: string;
topic?: string;
avatar_file_id?: string;
}
/**
* P2P contacts are keyed by their `p2p...` topic after the first subscription,
* while the friends API identifies the same person with a `usr...` user ID.
* Keep both aliases so avatars work during both the initial and established
* conversation states.
*/
export function friendAvatarLookup(friends: FriendAvatarSource[] = []) {
const avatars = new Map<string, string | undefined>();
for (const friend of friends) {
if (friend.user_id) avatars.set(friend.user_id, friend.avatar_file_id);
if (friend.topic) avatars.set(friend.topic, friend.avatar_file_id);
}
return avatars;
}
+24
View File
@@ -0,0 +1,24 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import { friendAvatarLookup } from '../src/features/messages/chat-list.ts';
test('friend avatars resolve by both user ID and established P2P topic', () => {
const avatars = friendAvatarLookup([
{
user_id: 'usr-potter',
topic: 'p2p-potter',
avatar_file_id: 'https://example.com/potter.png',
},
]);
assert.equal(avatars.get('usr-potter'), 'https://example.com/potter.png');
assert.equal(avatars.get('p2p-potter'), 'https://example.com/potter.png');
});
test('friend avatar lookup tolerates a new conversation without a topic alias', () => {
const avatars = friendAvatarLookup([{ user_id: 'usr-new', avatar_file_id: 'avatar-file-id' }]);
assert.equal(avatars.get('usr-new'), 'avatar-file-id');
assert.equal(avatars.has(''), false);
});