feat: refactor thought threads handling to improve structure and efficiency
This commit is contained in:
@@ -31,7 +31,10 @@ async function FeedPage({ token }: { token: string }) {
|
||||
getMe(token).catch(() => null) as Promise<Me | null>,
|
||||
]);
|
||||
|
||||
const authors = [...new Set(feedData.thoughts.map((t) => t.authorUsername))];
|
||||
const allThoughts = feedData.thoughts;
|
||||
const thoughtThreads = buildThoughtThreads(feedData.thoughts);
|
||||
|
||||
const authors = [...new Set(allThoughts.map((t) => t.authorUsername))];
|
||||
const userProfiles = await Promise.all(
|
||||
authors.map((username) => getUserProfile(username, token).catch(() => null))
|
||||
);
|
||||
@@ -42,12 +45,8 @@ async function FeedPage({ token }: { token: string }) {
|
||||
.map((user) => [user.username, { avatarUrl: user.avatarUrl }])
|
||||
);
|
||||
|
||||
const { topLevelThoughts, repliesByParentId } = buildThoughtThreads(
|
||||
feedData.thoughts
|
||||
);
|
||||
|
||||
const friends = (await getFriends(token)).users.map((user) => user.username);
|
||||
const shouldDisplayTopFriends = me?.topFriends && me.topFriends.length > 8;
|
||||
const shouldDisplayTopFriends = me?.topFriends && me.topFriends.length > 0;
|
||||
|
||||
return (
|
||||
<div className="container mx-auto max-w-6xl p-4 sm:p-6">
|
||||
@@ -65,16 +64,15 @@ async function FeedPage({ token }: { token: string }) {
|
||||
</header>
|
||||
<PostThoughtForm />
|
||||
<div className="space-y-6">
|
||||
{topLevelThoughts.map((thought) => (
|
||||
{thoughtThreads.map((thought) => (
|
||||
<ThoughtThread
|
||||
key={thought.id}
|
||||
thought={thought}
|
||||
repliesByParentId={repliesByParentId}
|
||||
authorDetails={authorDetails}
|
||||
currentUser={me}
|
||||
/>
|
||||
))}
|
||||
{topLevelThoughts.length === 0 && (
|
||||
{thoughtThreads.length === 0 && (
|
||||
<p className="text-center text-muted-foreground pt-8">
|
||||
Your feed is empty. Follow some users to see their thoughts!
|
||||
</p>
|
||||
|
@@ -24,6 +24,7 @@ export default async function TagPage({ params }: TagPageProps) {
|
||||
}
|
||||
|
||||
const allThoughts = thoughtsResult.value.thoughts;
|
||||
const thoughtThreads = buildThoughtThreads(allThoughts);
|
||||
const me = meResult.status === "fulfilled" ? (meResult.value as Me) : null;
|
||||
|
||||
const authors = [...new Set(allThoughts.map((t) => t.authorUsername))];
|
||||
@@ -36,9 +37,6 @@ export default async function TagPage({ params }: TagPageProps) {
|
||||
.map((user) => [user.username, { avatarUrl: user.avatarUrl }])
|
||||
);
|
||||
|
||||
const { topLevelThoughts, repliesByParentId } =
|
||||
buildThoughtThreads(allThoughts);
|
||||
|
||||
return (
|
||||
<div className="container mx-auto max-w-2xl p-4 sm:p-6">
|
||||
<header className="my-6">
|
||||
@@ -48,16 +46,15 @@ export default async function TagPage({ params }: TagPageProps) {
|
||||
</h1>
|
||||
</header>
|
||||
<main className="space-y-6">
|
||||
{topLevelThoughts.map((thought) => (
|
||||
{thoughtThreads.map((thought) => (
|
||||
<ThoughtThread
|
||||
key={thought.id}
|
||||
thought={thought}
|
||||
repliesByParentId={repliesByParentId}
|
||||
authorDetails={authorDetails}
|
||||
currentUser={me}
|
||||
/>
|
||||
))}
|
||||
{topLevelThoughts.length === 0 && (
|
||||
{thoughtThreads.length === 0 && (
|
||||
<p className="text-center text-muted-foreground pt-8">
|
||||
No thoughts found for this tag.
|
||||
</p>
|
||||
|
@@ -1,13 +1,12 @@
|
||||
import { cookies } from "next/headers";
|
||||
import {
|
||||
getThoughtById,
|
||||
getUserThoughts,
|
||||
getThoughtThread,
|
||||
getUserProfile,
|
||||
getMe,
|
||||
Me,
|
||||
Thought,
|
||||
User,
|
||||
ThoughtThread as ThoughtThreadType,
|
||||
} from "@/lib/api";
|
||||
import { buildThoughtThreads } from "@/lib/utils";
|
||||
import { ThoughtThread } from "@/components/thought-thread";
|
||||
import { notFound } from "next/navigation";
|
||||
|
||||
@@ -15,57 +14,43 @@ interface ThoughtPageProps {
|
||||
params: { thoughtId: string };
|
||||
}
|
||||
|
||||
async function findConversationRoot(
|
||||
startThought: Thought,
|
||||
token: string | null
|
||||
): Promise<Thought> {
|
||||
let currentThought = startThought;
|
||||
while (currentThought.replyToId) {
|
||||
const parentThought = await getThoughtById(
|
||||
currentThought.replyToId,
|
||||
token
|
||||
).catch(() => null);
|
||||
if (!parentThought) break;
|
||||
currentThought = parentThought;
|
||||
function collectAuthors(thread: ThoughtThreadType): string[] {
|
||||
const authors = new Set<string>([thread.authorUsername]);
|
||||
for (const reply of thread.replies) {
|
||||
collectAuthors(reply).forEach((author) => authors.add(author));
|
||||
}
|
||||
return currentThought;
|
||||
return Array.from(authors);
|
||||
}
|
||||
|
||||
export default async function ThoughtPage({ params }: ThoughtPageProps) {
|
||||
const { thoughtId } = params;
|
||||
const token = (await cookies()).get("auth_token")?.value ?? null;
|
||||
|
||||
const initialThought = await getThoughtById(thoughtId, token).catch(
|
||||
() => null
|
||||
);
|
||||
|
||||
if (!initialThought) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
const rootThought = await findConversationRoot(initialThought, token);
|
||||
|
||||
const [thoughtsResult, meResult] = await Promise.allSettled([
|
||||
getUserThoughts(rootThought.authorUsername, token),
|
||||
const [threadResult, meResult] = await Promise.allSettled([
|
||||
getThoughtThread(thoughtId, token),
|
||||
token ? getMe(token) : Promise.resolve(null),
|
||||
]);
|
||||
|
||||
if (thoughtsResult.status === "rejected") {
|
||||
if (threadResult.status === "rejected") {
|
||||
notFound();
|
||||
}
|
||||
|
||||
const allThoughts = thoughtsResult.value.thoughts;
|
||||
const thread = threadResult.value;
|
||||
const me = meResult.status === "fulfilled" ? (meResult.value as Me) : null;
|
||||
|
||||
const author = await getUserProfile(rootThought.authorUsername, token).catch(
|
||||
() => null
|
||||
// Fetch details for all authors in the thread efficiently
|
||||
const authorUsernames = collectAuthors(thread);
|
||||
const userProfiles = await Promise.all(
|
||||
authorUsernames.map((username) =>
|
||||
getUserProfile(username, token).catch(() => null)
|
||||
)
|
||||
);
|
||||
const authorDetails = new Map<string, { avatarUrl?: string | null }>();
|
||||
if (author) {
|
||||
authorDetails.set(author.username, { avatarUrl: author.avatarUrl });
|
||||
}
|
||||
|
||||
const { repliesByParentId } = buildThoughtThreads(allThoughts);
|
||||
const authorDetails = new Map<string, { avatarUrl?: string | null }>(
|
||||
userProfiles
|
||||
.filter((u): u is User => !!u)
|
||||
.map((user) => [user.username, { avatarUrl: user.avatarUrl }])
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="container mx-auto max-w-2xl p-4 sm:p-6">
|
||||
@@ -74,8 +59,7 @@ export default async function ThoughtPage({ params }: ThoughtPageProps) {
|
||||
</header>
|
||||
<main>
|
||||
<ThoughtThread
|
||||
thought={rootThought}
|
||||
repliesByParentId={repliesByParentId}
|
||||
thought={thread}
|
||||
authorDetails={authorDetails}
|
||||
currentUser={me}
|
||||
/>
|
||||
|
@@ -56,7 +56,7 @@ export default async function ProfilePage({ params }: ProfilePageProps) {
|
||||
|
||||
const thoughts =
|
||||
thoughtsResult.status === "fulfilled" ? thoughtsResult.value.thoughts : [];
|
||||
const { topLevelThoughts, repliesByParentId } = buildThoughtThreads(thoughts);
|
||||
const thoughtThreads = buildThoughtThreads(thoughts);
|
||||
|
||||
const followersCount =
|
||||
followersResult.status === "fulfilled"
|
||||
@@ -205,16 +205,15 @@ export default async function ProfilePage({ params }: ProfilePageProps) {
|
||||
id="profile-card__thoughts"
|
||||
className="col-span-1 lg:col-span-3 space-y-4"
|
||||
>
|
||||
{topLevelThoughts.map((thought) => (
|
||||
{thoughtThreads.map((thought) => (
|
||||
<ThoughtThread
|
||||
key={thought.id}
|
||||
thought={thought}
|
||||
repliesByParentId={repliesByParentId}
|
||||
authorDetails={authorDetails}
|
||||
currentUser={me}
|
||||
/>
|
||||
))}
|
||||
{topLevelThoughts.length === 0 && (
|
||||
{thoughtThreads.length === 0 && (
|
||||
<Card
|
||||
id="profile-card__no-thoughts"
|
||||
className="flex items-center justify-center h-48"
|
||||
|
Reference in New Issue
Block a user