From 44385adb6b1c9065c6d7f3d6817218e1c10d325a Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Thu, 14 May 2026 17:14:27 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20update=20frontend=20to=20work=20with=20?= =?UTF-8?q?v2=20backend=20=E2=80=94=20camelCase,=20new=20endpoints,=20nest?= =?UTF-8?q?ed=20author?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- thoughts-frontend/app/(auth)/login/page.tsx | 10 +- thoughts-frontend/app/page.tsx | 15 +- thoughts-frontend/app/search/page.tsx | 10 +- .../app/settings/api-keys/page.tsx | 4 +- thoughts-frontend/app/tags/[tagName]/page.tsx | 4 +- .../app/thoughts/[thoughtId]/page.tsx | 2 +- .../app/users/[username]/followers/page.tsx | 2 +- .../app/users/[username]/following/page.tsx | 2 +- .../app/users/[username]/page.tsx | 19 +- .../components/api-keys-list.tsx | 4 +- .../components/edit-profile-form.tsx | 22 -- .../components/post-thought-form.tsx | 17 +- thoughts-frontend/components/reply-form.tsx | 4 +- thoughts-frontend/components/thought-card.tsx | 2 +- thoughts-frontend/components/thought-list.tsx | 6 +- .../components/thought-thread.tsx | 6 +- thoughts-frontend/lib/api.ts | 360 +++++++----------- 17 files changed, 203 insertions(+), 286 deletions(-) diff --git a/thoughts-frontend/app/(auth)/login/page.tsx b/thoughts-frontend/app/(auth)/login/page.tsx index 963d8c6..f7838a5 100644 --- a/thoughts-frontend/app/(auth)/login/page.tsx +++ b/thoughts-frontend/app/(auth)/login/page.tsx @@ -33,7 +33,7 @@ export default function LoginPage() { const form = useForm>({ resolver: zodResolver(LoginSchema), - defaultValues: { username: "", password: "" }, + defaultValues: { email: "", password: "" }, }); async function onSubmit(values: z.infer) { @@ -43,7 +43,7 @@ export default function LoginPage() { setToken(token); router.push("/"); // Redirect to homepage on successful login } catch { - setError("Invalid username or password."); + setError("Invalid email or password."); } } @@ -61,12 +61,12 @@ export default function LoginPage() { {/* ... Form fields for username and password ... */} ( - Username + Email - + diff --git a/thoughts-frontend/app/page.tsx b/thoughts-frontend/app/page.tsx index 2a64c1d..39a3dea 100644 --- a/thoughts-frontend/app/page.tsx +++ b/thoughts-frontend/app/page.tsx @@ -3,6 +3,7 @@ import { getFeed, getFriends, getMe, + getTopFriends, getUserProfile, Me, User, @@ -60,7 +61,7 @@ async function FeedPage({ const { items: allThoughts, totalPages } = feedData!; const thoughtThreads = buildThoughtThreads(allThoughts); - const authors = [...new Set(allThoughts.map((t) => t.authorUsername))]; + const authors = [...new Set(allThoughts.map((t) => t.author.username))]; const userProfiles = await Promise.all( authors.map((username) => getUserProfile(username, token).catch(() => null)) ); @@ -72,10 +73,10 @@ async function FeedPage({ ); const friends = (await getFriends(token)).users.map((user) => user.username); - const shouldDisplayTopFriends = - token && me?.topFriends && me.topFriends.length > 8; - - console.log("Should display top friends:", shouldDisplayTopFriends); + const topFriendsData = me + ? await getTopFriends(me.username, token).catch(() => ({ topFriends: [] })) + : { topFriends: [] }; + const shouldDisplayTopFriends = topFriendsData.topFriends.length > 0; return (
@@ -96,7 +97,7 @@ async function FeedPage({
{shouldDisplayTopFriends && ( - + )} {!shouldDisplayTopFriends && token && friends.length > 0 && ( @@ -141,7 +142,7 @@ async function FeedPage({
{shouldDisplayTopFriends && ( - + )} {!shouldDisplayTopFriends && token && friends.length > 0 && ( diff --git a/thoughts-frontend/app/search/page.tsx b/thoughts-frontend/app/search/page.tsx index 99d9296..50d1270 100644 --- a/thoughts-frontend/app/search/page.tsx +++ b/thoughts-frontend/app/search/page.tsx @@ -30,7 +30,7 @@ export default async function SearchPage({ searchParams }: SearchPageProps) { const authorDetails = new Map(); if (results) { - results.users.users.forEach((user: User) => { + results.users.forEach((user: User) => { authorDetails.set(user.username, { avatarUrl: user.avatarUrl }); }); } @@ -48,21 +48,21 @@ export default async function SearchPage({ searchParams }: SearchPageProps) { - Thoughts ({results.thoughts.thoughts.length}) + Thoughts ({results.thoughts.length}) - Users ({results.users.users.length}) + Users ({results.users.length}) - + ) : ( diff --git a/thoughts-frontend/app/settings/api-keys/page.tsx b/thoughts-frontend/app/settings/api-keys/page.tsx index 629b071..3f1d198 100644 --- a/thoughts-frontend/app/settings/api-keys/page.tsx +++ b/thoughts-frontend/app/settings/api-keys/page.tsx @@ -10,7 +10,7 @@ export default async function ApiKeysPage() { } const initialApiKeys = await getApiKeys(token).catch(() => ({ - apiKeys: [], + keys: [], })); return ( @@ -21,7 +21,7 @@ export default async function ApiKeysPage() { Manage API keys for third-party applications.

- +
); } diff --git a/thoughts-frontend/app/tags/[tagName]/page.tsx b/thoughts-frontend/app/tags/[tagName]/page.tsx index 696bb32..6d38a90 100644 --- a/thoughts-frontend/app/tags/[tagName]/page.tsx +++ b/thoughts-frontend/app/tags/[tagName]/page.tsx @@ -23,11 +23,11 @@ export default async function TagPage({ params }: TagPageProps) { notFound(); } - const allThoughts = thoughtsResult.value.thoughts; + const allThoughts = thoughtsResult.value.items; const thoughtThreads = buildThoughtThreads(allThoughts); const me = meResult.status === "fulfilled" ? (meResult.value as Me) : null; - const authors = [...new Set(allThoughts.map((t) => t.authorUsername))]; + const authors = [...new Set(allThoughts.map((t) => t.author.username))]; const userProfiles = await Promise.all( authors.map((username) => getUserProfile(username, token).catch(() => null)) ); diff --git a/thoughts-frontend/app/thoughts/[thoughtId]/page.tsx b/thoughts-frontend/app/thoughts/[thoughtId]/page.tsx index 722f474..779ad7b 100644 --- a/thoughts-frontend/app/thoughts/[thoughtId]/page.tsx +++ b/thoughts-frontend/app/thoughts/[thoughtId]/page.tsx @@ -15,7 +15,7 @@ interface ThoughtPageProps { } function collectAuthors(thread: ThoughtThreadType): string[] { - const authors = new Set([thread.authorUsername]); + const authors = new Set([thread.author.username]); for (const reply of thread.replies) { collectAuthors(reply).forEach((author) => authors.add(author)); } diff --git a/thoughts-frontend/app/users/[username]/followers/page.tsx b/thoughts-frontend/app/users/[username]/followers/page.tsx index 4f8e41d..cbcefb5 100644 --- a/thoughts-frontend/app/users/[username]/followers/page.tsx +++ b/thoughts-frontend/app/users/[username]/followers/page.tsx @@ -26,7 +26,7 @@ export default async function FollowersPage({ params }: FollowersPageProps) {

Users following @{username}.

- +
); diff --git a/thoughts-frontend/app/users/[username]/following/page.tsx b/thoughts-frontend/app/users/[username]/following/page.tsx index a12af39..c59d0d6 100644 --- a/thoughts-frontend/app/users/[username]/following/page.tsx +++ b/thoughts-frontend/app/users/[username]/following/page.tsx @@ -26,7 +26,7 @@ export default async function FollowingPage({ params }: FollowingPageProps) {

Users that @{username} follows.

- +
); diff --git a/thoughts-frontend/app/users/[username]/page.tsx b/thoughts-frontend/app/users/[username]/page.tsx index 1962797..b0b87cf 100644 --- a/thoughts-frontend/app/users/[username]/page.tsx +++ b/thoughts-frontend/app/users/[username]/page.tsx @@ -3,6 +3,7 @@ import { getFollowingList, getFriends, getMe, + getTopFriends, getUserProfile, getUserThoughts, Me, @@ -55,33 +56,31 @@ export default async function ProfilePage({ params }: ProfilePageProps) { const me = meResult.status === "fulfilled" ? (meResult.value as Me) : null; const thoughts = - thoughtsResult.status === "fulfilled" ? thoughtsResult.value.thoughts : []; + thoughtsResult.status === "fulfilled" ? thoughtsResult.value.items : []; const thoughtThreads = buildThoughtThreads(thoughts); const followersCount = followersResult.status === "fulfilled" - ? followersResult.value.users.length + ? followersResult.value.total : 0; const followingCount = followingResult.status === "fulfilled" - ? followingResult.value.users.length + ? followingResult.value.total : 0; const isOwnProfile = me?.username === user.username; - const isFollowing = - me?.following?.some( - (followedUser) => followedUser.username === user.username - ) || false; + const isFollowing = user.isFollowedByViewer; const authorDetails = new Map(); authorDetails.set(user.username, { avatarUrl: user.avatarUrl }); const friends = typeof token === "string" - ? (await getFriends(token)).users.map((user) => user.username) + ? (await getFriends(token)).users.map((u) => u.username) : []; - const shouldDisplayTopFriends = token && friends.length > 8; + const topFriendsData = await getTopFriends(username, token).catch(() => ({ topFriends: [] })); + const shouldDisplayTopFriends = topFriendsData.topFriends.length > 0; return (
@@ -195,7 +194,7 @@ export default async function ProfilePage({ params }: ProfilePageProps) { {shouldDisplayTopFriends && ( - + )} {token && }
diff --git a/thoughts-frontend/components/api-keys-list.tsx b/thoughts-frontend/components/api-keys-list.tsx index 7fd8486..ba1368b 100644 --- a/thoughts-frontend/components/api-keys-list.tsx +++ b/thoughts-frontend/components/api-keys-list.tsx @@ -64,7 +64,7 @@ export function ApiKeyList({ initialApiKeys }: ApiKeyListProps) { try { const newKeyResponse = await createApiKey(values, token); setKeys((prev) => [...prev, newKeyResponse]); - setNewKey(newKeyResponse.plaintextKey ?? null); + setNewKey(newKeyResponse.key ?? null); form.reset(); toast.success("API Key created successfully."); } catch { @@ -113,7 +113,7 @@ export function ApiKeyList({ initialApiKeys }: ApiKeyListProps) { {`Created on ${format(key.createdAt, "PPP")}`}

- {`${key.keyPrefix}...`} + {key.id}

diff --git a/thoughts-frontend/components/edit-profile-form.tsx b/thoughts-frontend/components/edit-profile-form.tsx index 53874b7..5c17ca0 100644 --- a/thoughts-frontend/components/edit-profile-form.tsx +++ b/thoughts-frontend/components/edit-profile-form.tsx @@ -16,11 +16,9 @@ import { FormLabel, FormControl, FormMessage, - FormDescription, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; -import { TopFriendsCombobox } from "@/components/top-friends-combobox"; interface EditProfileFormProps { currentUser: Me; @@ -38,7 +36,6 @@ export function EditProfileForm({ currentUser }: EditProfileFormProps) { avatarUrl: currentUser.avatarUrl ?? undefined, headerUrl: currentUser.headerUrl ?? undefined, customCss: currentUser.customCss ?? undefined, - topFriends: currentUser.topFriends ?? [], }, }); @@ -135,25 +132,6 @@ export function EditProfileForm({ currentUser }: EditProfileFormProps) { )} /> - ( - - Top Friends - - - - - Select up to 8 of your friends to display on your profile. - - - - )} - />