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
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:
@@ -422,9 +422,11 @@ impl ActivityPubService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let domain = remote_actor.ap_id.host_str().unwrap_or("");
|
||||||
|
let full_handle = format!("{}@{}", remote_actor.username, domain);
|
||||||
let remote = RemoteActor {
|
let remote = RemoteActor {
|
||||||
url: remote_actor.ap_id.to_string(),
|
url: remote_actor.ap_id.to_string(),
|
||||||
handle: remote_actor.username.clone(),
|
handle: full_handle,
|
||||||
inbox_url: remote_actor.inbox_url.to_string(),
|
inbox_url: remote_actor.inbox_url.to_string(),
|
||||||
shared_inbox_url: None,
|
shared_inbox_url: None,
|
||||||
display_name: Some(remote_actor.username.clone()),
|
display_name: Some(remote_actor.username.clone()),
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import {
|
|||||||
getFollowersList,
|
getFollowersList,
|
||||||
getFollowingList,
|
getFollowingList,
|
||||||
getMe,
|
getMe,
|
||||||
|
getRemoteFollowers,
|
||||||
|
getRemoteFollowing,
|
||||||
getTopFriends,
|
getTopFriends,
|
||||||
getUserProfile,
|
getUserProfile,
|
||||||
getUserThoughts,
|
getUserThoughts,
|
||||||
@@ -95,16 +97,27 @@ export default async function ProfilePage({ params }: ProfilePageProps) {
|
|||||||
thoughtsResult.status === "fulfilled" ? thoughtsResult.value.items : [];
|
thoughtsResult.status === "fulfilled" ? thoughtsResult.value.items : [];
|
||||||
const thoughtThreads = buildThoughtThreads(thoughts);
|
const thoughtThreads = buildThoughtThreads(thoughts);
|
||||||
|
|
||||||
const followersCount =
|
const localFollowersCount =
|
||||||
followersResult.status === "fulfilled"
|
followersResult.status === "fulfilled"
|
||||||
? followersResult.value.total
|
? followersResult.value.total
|
||||||
: 0;
|
: 0;
|
||||||
const followingCount =
|
const localFollowingCount =
|
||||||
followingResult.status === "fulfilled"
|
followingResult.status === "fulfilled"
|
||||||
? followingResult.value.total
|
? followingResult.value.total
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
const isOwnProfile = me?.username === user.username;
|
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 isFollowing = user.isFollowedByViewer;
|
||||||
|
|
||||||
const apiDomain = process.env.NEXT_PUBLIC_API_URL
|
const apiDomain = process.env.NEXT_PUBLIC_API_URL
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { UserAvatar } from "@/components/user-avatar";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import { fullFediverseHandle } from "@/lib/utils";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
compact?: boolean;
|
compact?: boolean;
|
||||||
@@ -71,7 +72,7 @@ export function PendingRequests({ compact = false }: Props) {
|
|||||||
{actor.displayName || actor.handle}
|
{actor.displayName || actor.handle}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs text-muted-foreground truncate font-mono">
|
<p className="text-xs text-muted-foreground truncate font-mono">
|
||||||
@{actor.handle}
|
@{fullFediverseHandle(actor.handle, actor.url)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { UserAvatar } from "@/components/user-avatar";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import { fullFediverseHandle } from "@/lib/utils";
|
||||||
|
|
||||||
export function RemoteFollowers() {
|
export function RemoteFollowers() {
|
||||||
const { token } = useAuth();
|
const { token } = useAuth();
|
||||||
@@ -51,7 +52,7 @@ export function RemoteFollowers() {
|
|||||||
{actor.displayName || actor.handle}
|
{actor.displayName || actor.handle}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs text-muted-foreground truncate font-mono">
|
<p className="text-xs text-muted-foreground truncate font-mono">
|
||||||
@{actor.handle}
|
@{fullFediverseHandle(actor.handle, actor.url)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { UserAvatar } from "@/components/user-avatar";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import { fullFediverseHandle } from "@/lib/utils";
|
||||||
|
|
||||||
export function RemoteFollowing() {
|
export function RemoteFollowing() {
|
||||||
const { token } = useAuth();
|
const { token } = useAuth();
|
||||||
@@ -51,7 +52,7 @@ export function RemoteFollowing() {
|
|||||||
{actor.displayName || actor.handle}
|
{actor.displayName || actor.handle}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs text-muted-foreground truncate font-mono">
|
<p className="text-xs text-muted-foreground truncate font-mono">
|
||||||
@{actor.handle}
|
@{fullFediverseHandle(actor.handle, actor.url)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -6,6 +6,17 @@ export function cn(...inputs: ClassValue[]) {
|
|||||||
return twMerge(clsx(inputs))
|
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[] {
|
export function buildThoughtThreads(thoughts: Thought[]): ThoughtThreadType[] {
|
||||||
const thoughtMap = new Map<string, Thought>();
|
const thoughtMap = new Map<string, Thought>();
|
||||||
thoughts.forEach((t) => thoughtMap.set(t.id, t));
|
thoughts.forEach((t) => thoughtMap.set(t.id, t));
|
||||||
|
|||||||
Reference in New Issue
Block a user