fix: full fediverse handle display + follower count includes remote
Some checks failed
lint / lint (push) Has been cancelled
test / unit (push) Has been cancelled
test / integration (push) Has been cancelled
lint / lint (pull_request) Has been cancelled
test / unit (pull_request) Has been cancelled
test / integration (pull_request) Has been cancelled

This commit is contained in:
2026-05-15 04:35:04 +02:00
parent 4342a06319
commit 2e3b81de17
6 changed files with 35 additions and 6 deletions

View File

@@ -3,6 +3,8 @@ import {
getFollowersList,
getFollowingList,
getMe,
getRemoteFollowers,
getRemoteFollowing,
getTopFriends,
getUserProfile,
getUserThoughts,
@@ -95,16 +97,27 @@ export default async function ProfilePage({ params }: ProfilePageProps) {
thoughtsResult.status === "fulfilled" ? thoughtsResult.value.items : [];
const thoughtThreads = buildThoughtThreads(thoughts);
const followersCount =
const localFollowersCount =
followersResult.status === "fulfilled"
? followersResult.value.total
: 0;
const followingCount =
const localFollowingCount =
followingResult.status === "fulfilled"
? followingResult.value.total
: 0;
const isOwnProfile = me?.username === user.username;
const [remoteFollowersCount, remoteFollowingCount] =
isOwnProfile && token
? await Promise.all([
getRemoteFollowers(token).then((r) => r.length).catch(() => 0),
getRemoteFollowing(token).then((r) => r.length).catch(() => 0),
])
: [0, 0];
const followersCount = localFollowersCount + remoteFollowersCount;
const followingCount = localFollowingCount + remoteFollowingCount;
const isFollowing = user.isFollowedByViewer;
const apiDomain = process.env.NEXT_PUBLIC_API_URL

View File

@@ -12,6 +12,7 @@ import { UserAvatar } from "@/components/user-avatar";
import { Button } from "@/components/ui/button";
import { toast } from "sonner";
import Link from "next/link";
import { fullFediverseHandle } from "@/lib/utils";
interface Props {
compact?: boolean;
@@ -71,7 +72,7 @@ export function PendingRequests({ compact = false }: Props) {
{actor.displayName || actor.handle}
</p>
<p className="text-xs text-muted-foreground truncate font-mono">
@{actor.handle}
@{fullFediverseHandle(actor.handle, actor.url)}
</p>
</div>
</Link>

View File

@@ -7,6 +7,7 @@ import { UserAvatar } from "@/components/user-avatar";
import { Button } from "@/components/ui/button";
import { toast } from "sonner";
import Link from "next/link";
import { fullFediverseHandle } from "@/lib/utils";
export function RemoteFollowers() {
const { token } = useAuth();
@@ -51,7 +52,7 @@ export function RemoteFollowers() {
{actor.displayName || actor.handle}
</p>
<p className="text-xs text-muted-foreground truncate font-mono">
@{actor.handle}
@{fullFediverseHandle(actor.handle, actor.url)}
</p>
</div>
</Link>

View File

@@ -7,6 +7,7 @@ import { UserAvatar } from "@/components/user-avatar";
import { Button } from "@/components/ui/button";
import { toast } from "sonner";
import Link from "next/link";
import { fullFediverseHandle } from "@/lib/utils";
export function RemoteFollowing() {
const { token } = useAuth();
@@ -51,7 +52,7 @@ export function RemoteFollowing() {
{actor.displayName || actor.handle}
</p>
<p className="text-xs text-muted-foreground truncate font-mono">
@{actor.handle}
@{fullFediverseHandle(actor.handle, actor.url)}
</p>
</div>
</Link>

View File

@@ -6,6 +6,17 @@ export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
/** Construct a full fediverse handle like `user@instance.social`.
* Falls back gracefully for existing DB rows that only stored the username. */
export function fullFediverseHandle(handle: string, actorUrl: string): string {
if (handle.includes("@")) return handle;
try {
return `${handle}@${new URL(actorUrl).hostname}`;
} catch {
return handle;
}
}
export function buildThoughtThreads(thoughts: Thought[]): ThoughtThreadType[] {
const thoughtMap = new Map<string, Thought>();
thoughts.forEach((t) => thoughtMap.set(t.id, t));