fix p2p conversation avatars
This commit is contained in:
@@ -6,6 +6,7 @@ import { Link, useLocation, useNavigate, useParams } from 'react-router-dom';
|
|||||||
import { Avatar } from '@/app/Avatar';
|
import { Avatar } from '@/app/Avatar';
|
||||||
import { Icon } from '@/app/Icon';
|
import { Icon } from '@/app/Icon';
|
||||||
import { CreateGroupModal } from '@/features/groups/CreateGroupModal';
|
import { CreateGroupModal } from '@/features/groups/CreateGroupModal';
|
||||||
|
import { friendAvatarLookup } from '@/features/messages/chat-list';
|
||||||
import { fetchAllPages } from '@/lib/api/client';
|
import { fetchAllPages } from '@/lib/api/client';
|
||||||
import { getFriends } from '@/lib/api/friends';
|
import { getFriends } from '@/lib/api/friends';
|
||||||
import { getGroups } from '@/lib/api/groups';
|
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
|
// 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.
|
// 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 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 [query, setQuery] = useState('');
|
||||||
const [creatingGroup, setCreatingGroup] = useState(false);
|
const [creatingGroup, setCreatingGroup] = useState(false);
|
||||||
const sorted = [...contacts].sort((a, b) => {
|
const sorted = [...contacts].sort((a, b) => {
|
||||||
@@ -158,7 +159,7 @@ export function ChatListColumn() {
|
|||||||
const memberCount = isGroup ? memberCountByTopic.get(contact.topic) : undefined;
|
const memberCount = isGroup ? memberCountByTopic.get(contact.topic) : undefined;
|
||||||
const muted = !!contact.private?.mute_notifications;
|
const muted = !!contact.private?.mute_notifications;
|
||||||
const avatarFileId =
|
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 (
|
return (
|
||||||
<Link
|
<Link
|
||||||
key={contact.topic}
|
key={contact.topic}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user