fix(federation): normalize federated username display across UI
Use parseFederatedUsername() consistently to show base username instead of raw user@domain format. Replace inline domain text in Username component with compact globe icon + tooltip. Add globe icons to DM header and sidebar for federated users.
This commit is contained in:
@@ -886,13 +886,15 @@ function TabButton({ children, active, onClick }: { children: React.ReactNode, a
|
||||
|
||||
function FriendItem({ friend, onRemove, onDm }: { friend: TaggedFriend, onRemove: () => void, onDm: () => void }) {
|
||||
const instanceLabel = friend._instanceOrigin ? (() => { try { return new URL(friend._instanceOrigin).host; } catch { return friend._instanceOrigin; } })() : '';
|
||||
const { baseName: friendBaseName } = parseFederatedUsername(friend.username);
|
||||
const friendDisplayName = friend.displayName ?? friendBaseName;
|
||||
return (
|
||||
<div className="flex items-center justify-between px-3 h-[62px] rounded-[8px] hover:bg-interactive-hover group transition-colors border-t border-interactive-muted mx-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<Avatar src={friend.avatar} name={friend.displayName ?? friend.username} size={32} status={friend.status} userId={friend.homeUserId ?? friend.id} avatarColor={friend.avatarColor} />
|
||||
<Avatar src={friend.avatar} name={friendDisplayName} size={32} status={friend.status} userId={friend.homeUserId ?? friend.id} avatarColor={friend.avatarColor} />
|
||||
<div className="flex flex-col leading-tight">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="text-txt-primary font-semibold text-[15px]">{friend.displayName ?? friend.username}</span>
|
||||
<span className="text-txt-primary font-semibold text-[15px]">{friendDisplayName}</span>
|
||||
<span className="text-txt-tertiary text-[13px] opacity-0 group-hover:opacity-100 transition-opacity font-medium">@{friend.username}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5">
|
||||
@@ -937,14 +939,16 @@ function RequestItem({ request, type, onAccept, onDecline, onCancel }: {
|
||||
const user = request.user;
|
||||
if (!user) return null;
|
||||
const instanceLabel = request._instanceOrigin ? (() => { try { return new URL(request._instanceOrigin).host; } catch { return request._instanceOrigin; } })() : '';
|
||||
const { baseName: reqBaseName } = parseFederatedUsername(user.username);
|
||||
const reqDisplayName = user.displayName ?? reqBaseName;
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between px-3 py-2.5 rounded-lg hover:bg-interactive-hover group transition-colors border-t border-interactive-muted mx-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<Avatar src={user.avatar} name={user.displayName ?? user.username} size={32} status={user.status as any} userId={user.homeUserId ?? user.id} avatarColor={user.avatarColor} />
|
||||
<Avatar src={user.avatar} name={reqDisplayName} size={32} status={user.status as any} userId={user.homeUserId ?? user.id} avatarColor={user.avatarColor} />
|
||||
<div className="flex flex-col">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="text-txt-primary font-bold text-sm">{user.displayName ?? user.username}</span>
|
||||
<span className="text-txt-primary font-bold text-sm">{reqDisplayName}</span>
|
||||
<span className="text-txt-tertiary text-xs">@{user.username}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5">
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useAuthStore } from '../../stores/authStore';
|
||||
import { useSocialStore } from '../../stores/socialStore';
|
||||
import { Avatar } from '../ui/Avatar';
|
||||
import { hasPermissionBit, PermissionBits } from '../../utils/permissions';
|
||||
import { isSelf } from '../../utils/identity';
|
||||
import { isSelf, parseFederatedUsername } from '../../utils/identity';
|
||||
import { useDelayedLoading } from '../../hooks/useDelayedLoading';
|
||||
import type { MessageWithUser } from '@backspace/shared';
|
||||
|
||||
@@ -374,8 +374,9 @@ function WelcomeHeader({ channelId }: { channelId: string }) {
|
||||
if (isDm) {
|
||||
const dm = dmChannels.find(d => d.id === channelId);
|
||||
const otherUser = dm?.members.find(m => !isSelf(m, authUser));
|
||||
const displayName = otherUser?.displayName ?? otherUser?.username ?? 'Unknown';
|
||||
const username = otherUser?.username ?? 'unknown';
|
||||
const { baseName } = parseFederatedUsername(otherUser?.username ?? 'unknown');
|
||||
const displayName = otherUser?.displayName ?? baseName;
|
||||
const username = baseName;
|
||||
const isFriend = otherUser ? friends.some(f => f.id === otherUser.id) : false;
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user