feat: load more pagination for user profile thoughts
This commit is contained in:
@@ -53,8 +53,7 @@ import { FollowButton } from "@/components/follow-button";
|
||||
import { TopFriends } from "@/components/top-friends";
|
||||
import { Suspense } from "react";
|
||||
import { ProfileSkeleton } from "@/components/loading-skeleton";
|
||||
import { buildThoughtThreads } from "@/lib/utils";
|
||||
import { ThoughtThread } from "@/components/thought-thread";
|
||||
import { UserThoughtsList } from "@/components/user-thoughts-list";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import Link from "next/link";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
@@ -95,9 +94,11 @@ export default async function ProfilePage({ params }: ProfilePageProps) {
|
||||
const user = userResult.value;
|
||||
const me = meResult.status === "fulfilled" ? (meResult.value as Me) : null;
|
||||
|
||||
const thoughts =
|
||||
thoughtsResult.status === "fulfilled" ? thoughtsResult.value.items : [];
|
||||
const thoughtThreads = buildThoughtThreads(thoughts);
|
||||
const thoughtsData = thoughtsResult.status === "fulfilled" ? thoughtsResult.value : null;
|
||||
const thoughts = thoughtsData?.items ?? [];
|
||||
const totalPages = thoughtsData
|
||||
? Math.ceil(thoughtsData.total / thoughtsData.per_page)
|
||||
: 1;
|
||||
|
||||
const localFollowersCount =
|
||||
followersResult.status === "fulfilled"
|
||||
@@ -262,16 +263,12 @@ export default async function ProfilePage({ params }: ProfilePageProps) {
|
||||
)}
|
||||
</TabsList>
|
||||
<TabsContent value="thoughts" className="space-y-4">
|
||||
{thoughtThreads.map((thought) => (
|
||||
<ThoughtThread
|
||||
key={thought.id}
|
||||
thought={thought}
|
||||
currentUser={me}
|
||||
/>
|
||||
))}
|
||||
{thoughtThreads.length === 0 && (
|
||||
<EmptyState emoji="💭" title="Nothing here yet" message="This user hasn't posted any public thoughts yet." />
|
||||
)}
|
||||
<UserThoughtsList
|
||||
username={username}
|
||||
initialThoughts={thoughts}
|
||||
totalPages={totalPages}
|
||||
me={me}
|
||||
/>
|
||||
</TabsContent>
|
||||
{isOwnProfile && (
|
||||
<TabsContent value="federation">
|
||||
|
||||
72
thoughts-frontend/components/user-thoughts-list.tsx
Normal file
72
thoughts-frontend/components/user-thoughts-list.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { getUserThoughts, Me, Thought } from "@/lib/api";
|
||||
import { ThoughtThread } from "@/components/thought-thread";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { EmptyState } from "@/components/empty-state";
|
||||
import { buildThoughtThreads } from "@/lib/utils";
|
||||
import { toast } from "sonner";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
|
||||
interface UserThoughtsListProps {
|
||||
username: string;
|
||||
initialThoughts: Thought[];
|
||||
totalPages: number;
|
||||
me: Me | null;
|
||||
}
|
||||
|
||||
export function UserThoughtsList({
|
||||
username,
|
||||
initialThoughts,
|
||||
totalPages,
|
||||
me,
|
||||
}: UserThoughtsListProps) {
|
||||
const [thoughts, setThoughts] = useState<Thought[]>(initialThoughts);
|
||||
const [page, setPage] = useState(1);
|
||||
const [loadingMore, setLoadingMore] = useState(false);
|
||||
const { token } = useAuth();
|
||||
|
||||
const thoughtThreads = buildThoughtThreads(thoughts);
|
||||
|
||||
const loadMore = async () => {
|
||||
setLoadingMore(true);
|
||||
try {
|
||||
const result = await getUserThoughts(username, token, page + 1);
|
||||
setThoughts((prev) => [...prev, ...result.items]);
|
||||
setPage((p) => p + 1);
|
||||
} catch {
|
||||
toast.error("Failed to load more thoughts.");
|
||||
} finally {
|
||||
setLoadingMore(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (thoughtThreads.length === 0) {
|
||||
return (
|
||||
<EmptyState
|
||||
emoji="💭"
|
||||
title="Nothing here yet"
|
||||
message="This user hasn't posted any public thoughts yet."
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{thoughtThreads.map((thought) => (
|
||||
<ThoughtThread key={thought.id} thought={thought} currentUser={me} />
|
||||
))}
|
||||
{page < totalPages && (
|
||||
<Button
|
||||
onClick={loadMore}
|
||||
disabled={loadingMore}
|
||||
variant="outline"
|
||||
className="w-full rounded-full"
|
||||
>
|
||||
{loadingMore ? "Loading…" : "Load more"}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -343,9 +343,9 @@ export const getFeed = (token: string, page: number = 1, pageSize: number = 20)
|
||||
token
|
||||
);
|
||||
|
||||
export const getUserThoughts = (username: string, token: string | null) =>
|
||||
export const getUserThoughts = (username: string, token: string | null, page = 1) =>
|
||||
apiFetch(
|
||||
`/users/${username}/thoughts`,
|
||||
`/users/${username}/thoughts?page=${page}`,
|
||||
{ next: { tags: [`profile:${username}`] } },
|
||||
z.object({ items: z.array(ThoughtSchema), total: z.number(), page: z.number(), per_page: z.number() }),
|
||||
token
|
||||
|
||||
Reference in New Issue
Block a user