feat: enhance profile and feed pages with friends display logic, update TopFriends component to support mode, and extend bio length in profile schema

This commit is contained in:
2025-09-07 13:37:39 +02:00
parent c9b8bd7b07
commit e1b5a2aaa0
6 changed files with 37 additions and 11 deletions

View File

@@ -5,7 +5,7 @@ export default function AuthLayout({
children: React.ReactNode; children: React.ReactNode;
}) { }) {
return ( return (
<div className="flex items-center justify-center min-h-screen bg-gray-100"> <div className="flex items-center justify-center min-h-screen">
{children} {children}
</div> </div>
); );

View File

@@ -1,5 +1,12 @@
import { cookies } from "next/headers"; import { cookies } from "next/headers";
import { getFeed, getMe, getUserProfile, Me, User } from "@/lib/api"; import {
getFeed,
getFriends,
getMe,
getUserProfile,
Me,
User,
} from "@/lib/api";
import { PostThoughtForm } from "@/components/post-thought-form"; import { PostThoughtForm } from "@/components/post-thought-form";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import Link from "next/link"; import Link from "next/link";
@@ -39,11 +46,14 @@ async function FeedPage({ token }: { token: string }) {
feedData.thoughts feedData.thoughts
); );
const friends = (await getFriends(token)).users.map((user) => user.username);
const shouldDisplayTopFriends = me?.topFriends && me.topFriends.length > 8;
return ( return (
<div className="container mx-auto max-w-6xl p-4 sm:p-6"> <div className="container mx-auto max-w-6xl p-4 sm:p-6">
<div className="grid grid-cols-1 lg:grid-cols-4 gap-8"> <div className="grid grid-cols-1 lg:grid-cols-4 gap-8">
<aside className="hidden lg:block lg:col-span-1"> <aside className="hidden lg:block lg:col-span-1">
<div className="sticky top-20 space-y-6"> <div className="sticky top-20 space-y-6 glass-effect glossy-effect bottom rounded-md p-4">
<h2 className="text-lg font-semibold">Filters & Sorting</h2> <h2 className="text-lg font-semibold">Filters & Sorting</h2>
<p className="text-sm text-muted-foreground">Coming soon...</p> <p className="text-sm text-muted-foreground">Coming soon...</p>
</div> </div>
@@ -74,8 +84,11 @@ async function FeedPage({ token }: { token: string }) {
<aside className="hidden lg:block lg:col-span-1"> <aside className="hidden lg:block lg:col-span-1">
<div className="sticky top-20 space-y-6"> <div className="sticky top-20 space-y-6">
{me?.topFriends && <TopFriends usernames={me.topFriends} />} {shouldDisplayTopFriends && (
<TopFriends mode="top-friends" usernames={me.topFriends} />
)}
<PopularTags /> <PopularTags />
{token && <TopFriends mode="friends" usernames={friends || []} />}
</div> </div>
</aside> </aside>
</div> </div>

View File

@@ -1,6 +1,7 @@
import { import {
getFollowersList, getFollowersList,
getFollowingList, getFollowingList,
getFriends,
getMe, getMe,
getUserProfile, getUserProfile,
getUserThoughts, getUserThoughts,
@@ -75,6 +76,13 @@ export default async function ProfilePage({ params }: ProfilePageProps) {
const authorDetails = new Map<string, { avatarUrl?: string | null }>(); const authorDetails = new Map<string, { avatarUrl?: string | null }>();
authorDetails.set(user.username, { avatarUrl: user.avatarUrl }); authorDetails.set(user.username, { avatarUrl: user.avatarUrl });
const friends =
typeof token === "string"
? (await getFriends(token)).users.map((user) => user.username)
: [];
const shouldDisplayTopFriends = token && friends.length > 8;
return ( return (
<div id={`profile-page-${user.username}`}> <div id={`profile-page-${user.username}`}>
{user.customCss && ( {user.customCss && (
@@ -186,7 +194,10 @@ export default async function ProfilePage({ params }: ProfilePageProps) {
</div> </div>
</Card> </Card>
<TopFriends usernames={user.topFriends} /> {shouldDisplayTopFriends && (
<TopFriends mode="top-friends" usernames={user.topFriends} />
)}
{token && <TopFriends mode="friends" usernames={friends || []} />}
</div> </div>
</aside> </aside>

View File

@@ -25,7 +25,7 @@ export function Header() {
<UserNav /> <UserNav />
) : ( ) : (
<> <>
<Button asChild variant="ghost" size="sm"> <Button asChild size="sm">
<Link href="/login">Login</Link> <Link href="/login">Login</Link>
</Button> </Button>
<Button asChild size="sm"> <Button asChild size="sm">

View File

@@ -5,11 +5,14 @@ import { getUserProfile, User } from "@/lib/api";
import { cookies } from "next/headers"; import { cookies } from "next/headers";
interface TopFriendsProps { interface TopFriendsProps {
mode: "friends" | "top-friends";
usernames: string[]; usernames: string[];
} }
// This is an async Server Component export async function TopFriends({
export async function TopFriends({ usernames }: TopFriendsProps) { mode = "top-friends",
usernames,
}: TopFriendsProps) {
const token = (await cookies()).get("auth_token")?.value ?? null; const token = (await cookies()).get("auth_token")?.value ?? null;
if (usernames.length === 0) { if (usernames.length === 0) {
@@ -27,7 +30,6 @@ export async function TopFriends({ usernames }: TopFriendsProps) {
); );
} }
// Fetch all top friend profiles in parallel
const friendsResults = await Promise.allSettled( const friendsResults = await Promise.allSettled(
usernames.map((username) => getUserProfile(username, token)) usernames.map((username) => getUserProfile(username, token))
); );
@@ -43,7 +45,7 @@ export async function TopFriends({ usernames }: TopFriendsProps) {
<Card id="top-friends" className="p-4"> <Card id="top-friends" className="p-4">
<CardHeader id="top-friends__header" className="p-0 pb-2"> <CardHeader id="top-friends__header" className="p-0 pb-2">
<CardTitle id="top-friends__title" className="text-lg text-shadow-md"> <CardTitle id="top-friends__title" className="text-lg text-shadow-md">
Top Friends {mode === "top-friends" ? "Top Friends" : "Friends"}
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent id="top-friends__content" className="p-0"> <CardContent id="top-friends__content" className="p-0">

View File

@@ -53,7 +53,7 @@ export const CreateThoughtSchema = z.object({
export const UpdateProfileSchema = z.object({ export const UpdateProfileSchema = z.object({
displayName: z.string().max(50).optional(), displayName: z.string().max(50).optional(),
bio: z.string().max(160).optional(), bio: z.string().max(4000).optional(),
avatarUrl: z.url().or(z.literal("")).optional(), avatarUrl: z.url().or(z.literal("")).optional(),
headerUrl: z.url().or(z.literal("")).optional(), headerUrl: z.url().or(z.literal("")).optional(),
customCss: z.string().optional(), customCss: z.string().optional(),