diff --git a/web/src/app/UserCardRoot.tsx b/web/src/app/UserCardRoot.tsx index 53d6753a..51d79a97 100644 --- a/web/src/app/UserCardRoot.tsx +++ b/web/src/app/UserCardRoot.tsx @@ -8,6 +8,7 @@ import { Icon } from '@/app/Icon'; import { AddFriendModal } from '@/features/contacts/AddFriendModal'; import { ImApiError } from '@/lib/api/client'; import { getUserProfile } from '@/lib/api/friends'; +import { getMyProfile } from '@/lib/api/profile'; import { useEscapeKey } from '@/lib/hooks'; import { useCallStore } from '@/stores/calls'; import { useSessionStore } from '@/stores/session'; @@ -40,11 +41,40 @@ function UserCardPanel({ userId }: { userId: string }) { const isSelf = !!myUserId && myUserId === userId; const [addingFriend, setAddingFriend] = useState(false); - const query = useQuery({ + // Real, live-confirmed bug (2026-09-25 review): `GET /users/{id}/profile` 400s on a SELF lookup, + // same self-lookup gap already documented and fixed elsewhere for the group-scoped equivalent + // (getMyGroupProfile's own comment, `lib/api/groups.ts`) -- tapping your OWN avatar (reachable from + // the member grid/list like anyone else's) always landed on the "加载失败,请重试" branch, retrying + // into the same 400 forever. Routes self through the dedicated `GET /me/profile` instead, which has + // no such restriction; normalized into the same shape the render below already expects so the two + // branches don't need two separate JSX trees. + const otherQuery = useQuery({ queryKey: ['user-profile', userId], queryFn: () => getUserProfile(userId), + enabled: !isSelf, }); - const profile = query.data; + const selfQuery = useQuery({ + queryKey: ['my-profile-card', userId], + queryFn: () => getMyProfile(), + enabled: isSelf, + }); + const query = isSelf ? selfQuery : otherQuery; + const profile = isSelf + ? selfQuery.data + ? { + user_id: userId, + display_name: selfQuery.data.nickname, + avatar_file_id: selfQuery.data.avatar_file_id, + gender: selfQuery.data.gender, + region: selfQuery.data.region, + signature: selfQuery.data.signature, + public_account: selfQuery.data.public_account, + relationship: 'self', + remark: undefined as string | undefined, + capabilities: undefined as { can_send?: boolean; can_call?: boolean; can_add_friend?: boolean } | undefined, + } + : undefined + : otherQuery.data; const name = profile ? profile.remark || profile.display_name : ''; // Real bug this fixes: this card's own doc comment always claimed "same relationship-aware action // gating" as FriendProfileView.tsx, but until now it never read `profile.relationship` at all --