perf(frontend): eliminate author profile waterfall — use thought.author directly
This commit is contained in:
@@ -91,11 +91,6 @@ export function RemoteUserProfile({
|
||||
|
||||
const isOwnProfile = me?.username === actor.handle;
|
||||
|
||||
const authorDetails = new Map<string, { avatarUrl?: string | null }>();
|
||||
initialPosts.forEach((t) => {
|
||||
authorDetails.set(t.author.username, { avatarUrl: actor.avatarUrl });
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
@@ -220,7 +215,6 @@ export function RemoteUserProfile({
|
||||
{initialPosts.length > 0 ? (
|
||||
<ThoughtList
|
||||
thoughts={initialPosts}
|
||||
authorDetails={authorDetails}
|
||||
currentUser={me}
|
||||
/>
|
||||
) : (
|
||||
|
||||
@@ -7,11 +7,11 @@ import {
|
||||
CardHeader,
|
||||
} from "@/components/ui/card";
|
||||
import { UserAvatar } from "./user-avatar";
|
||||
import { deleteThought, Me, Thought } from "@/lib/api";
|
||||
import { Me, Thought } from "@/lib/api";
|
||||
import { deleteThought } from "@/app/actions/thoughts";
|
||||
import { format, formatDistanceToNow } from "date-fns";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
DropdownMenu,
|
||||
@@ -42,25 +42,19 @@ import { cn } from "@/lib/utils";
|
||||
|
||||
interface ThoughtCardProps {
|
||||
thought: Thought;
|
||||
author: {
|
||||
username: string;
|
||||
displayName?: string | null;
|
||||
avatarUrl?: string | null;
|
||||
};
|
||||
currentUser: Me | null;
|
||||
isReply?: boolean;
|
||||
}
|
||||
|
||||
export function ThoughtCard({
|
||||
thought,
|
||||
author,
|
||||
currentUser,
|
||||
isReply = false,
|
||||
}: ThoughtCardProps) {
|
||||
const { author } = thought;
|
||||
const [isAlertOpen, setIsAlertOpen] = useState(false);
|
||||
const [isReplyOpen, setIsReplyOpen] = useState(false);
|
||||
const { token } = useAuth();
|
||||
const router = useRouter();
|
||||
const timeAgo = formatDistanceToNow(new Date(thought.createdAt), {
|
||||
addSuffix: true,
|
||||
});
|
||||
@@ -68,11 +62,9 @@ export function ThoughtCard({
|
||||
const isAuthor = currentUser?.username === thought.author.username;
|
||||
|
||||
const handleDelete = async () => {
|
||||
if (!token) return;
|
||||
try {
|
||||
await deleteThought(thought.id, token);
|
||||
await deleteThought(thought.id);
|
||||
toast.success("Thought deleted successfully.");
|
||||
router.refresh();
|
||||
} catch (error) {
|
||||
console.error("Failed to delete thought:", error);
|
||||
toast.error("Failed to delete thought.");
|
||||
|
||||
@@ -4,15 +4,10 @@ import { Card, CardContent } from "./ui/card";
|
||||
|
||||
interface ThoughtListProps {
|
||||
thoughts: Thought[];
|
||||
authorDetails: Map<string, { avatarUrl?: string | null }>;
|
||||
currentUser: Me | null;
|
||||
}
|
||||
|
||||
export function ThoughtList({
|
||||
thoughts,
|
||||
authorDetails,
|
||||
currentUser,
|
||||
}: ThoughtListProps) {
|
||||
export function ThoughtList({ thoughts, currentUser }: ThoughtListProps) {
|
||||
if (thoughts.length === 0) {
|
||||
return (
|
||||
<p className="text-center text-muted-foreground pt-8">
|
||||
@@ -25,21 +20,13 @@ export function ThoughtList({
|
||||
<Card>
|
||||
<CardContent className="divide-y p-0">
|
||||
<div className="space-y-6 p-4">
|
||||
{thoughts.map((thought) => {
|
||||
const author = {
|
||||
username: thought.author.username,
|
||||
displayName: thought.author.displayName,
|
||||
...authorDetails.get(thought.author.username),
|
||||
};
|
||||
return (
|
||||
<ThoughtCard
|
||||
key={thought.id}
|
||||
thought={thought}
|
||||
author={author}
|
||||
currentUser={currentUser}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{thoughts.map((thought) => (
|
||||
<ThoughtCard
|
||||
key={thought.id}
|
||||
thought={thought}
|
||||
currentUser={currentUser}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -3,29 +3,19 @@ import { ThoughtCard } from "./thought-card";
|
||||
|
||||
interface ThoughtThreadProps {
|
||||
thought: ThoughtThreadType;
|
||||
authorDetails: Map<string, { avatarUrl?: string | null }>;
|
||||
currentUser: Me | null;
|
||||
isReply?: boolean;
|
||||
}
|
||||
|
||||
export function ThoughtThread({
|
||||
thought,
|
||||
authorDetails,
|
||||
currentUser,
|
||||
isReply = false,
|
||||
}: ThoughtThreadProps) {
|
||||
const author = {
|
||||
username: thought.author.username,
|
||||
displayName: thought.author.displayName,
|
||||
avatarUrl: thought.author.avatarUrl, // API-provided avatar (from DB COALESCE)
|
||||
...authorDetails.get(thought.author.username), // override for local users
|
||||
};
|
||||
|
||||
return (
|
||||
<div id={`thought-thread-${thought.id}`} className="flex flex-col gap-0">
|
||||
<ThoughtCard
|
||||
thought={thought}
|
||||
author={author}
|
||||
currentUser={currentUser}
|
||||
isReply={isReply}
|
||||
/>
|
||||
@@ -39,7 +29,6 @@ export function ThoughtThread({
|
||||
<ThoughtThread
|
||||
key={reply.id}
|
||||
thought={reply}
|
||||
authorDetails={authorDetails}
|
||||
currentUser={currentUser}
|
||||
isReply={true}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user