diff --git a/thoughts-frontend/app/users/[username]/page.tsx b/thoughts-frontend/app/users/[username]/page.tsx index b78bb3f..aba0d58 100644 --- a/thoughts-frontend/app/users/[username]/page.tsx +++ b/thoughts-frontend/app/users/[username]/page.tsx @@ -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) { )} - {thoughtThreads.map((thought) => ( - - ))} - {thoughtThreads.length === 0 && ( - - )} + {isOwnProfile && ( diff --git a/thoughts-frontend/components/user-thoughts-list.tsx b/thoughts-frontend/components/user-thoughts-list.tsx new file mode 100644 index 0000000..b9e2a05 --- /dev/null +++ b/thoughts-frontend/components/user-thoughts-list.tsx @@ -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(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 ( + + ); + } + + return ( +
+ {thoughtThreads.map((thought) => ( + + ))} + {page < totalPages && ( + + )} +
+ ); +} diff --git a/thoughts-frontend/lib/api.ts b/thoughts-frontend/lib/api.ts index 1b8cc59..c6b2a27 100644 --- a/thoughts-frontend/lib/api.ts +++ b/thoughts-frontend/lib/api.ts @@ -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