diff --git a/thoughts-frontend/app/page.tsx b/thoughts-frontend/app/page.tsx index 08fb0b4..20ee490 100644 --- a/thoughts-frontend/app/page.tsx +++ b/thoughts-frontend/app/page.tsx @@ -1,6 +1,6 @@ // app/page.tsx import { cookies } from "next/headers"; -import { getFeed, getUserProfile } from "@/lib/api"; +import { getFeed, getMe, getUserProfile, Me } from "@/lib/api"; import { ThoughtCard } from "@/components/thought-card"; import { PostThoughtForm } from "@/components/post-thought-form"; import { Button } from "@/components/ui/button"; @@ -20,6 +20,7 @@ export default async function Home() { async function FeedPage({ token }: { token: string }) { const feedData = await getFeed(token); + const me = (await getMe(token).catch(() => null)) as Me | null; const authors = [...new Set(feedData.thoughts.map((t) => t.authorUsername))]; const userProfiles = await Promise.all( authors.map((username) => getUserProfile(username, token).catch(() => null)) @@ -46,6 +47,7 @@ async function FeedPage({ token }: { token: string }) { username: thought.authorUsername, avatarUrl: authorDetails.get(thought.authorUsername)?.avatarUrl, }} + currentUser={me} /> ))} {feedData.thoughts.length === 0 && ( diff --git a/thoughts-frontend/app/settings/profile/page.tsx b/thoughts-frontend/app/settings/profile/page.tsx new file mode 100644 index 0000000..cfab14d --- /dev/null +++ b/thoughts-frontend/app/settings/profile/page.tsx @@ -0,0 +1,39 @@ +import { cookies } from "next/headers"; +import { redirect } from "next/navigation"; +import { getMe } from "@/lib/api"; +import { + Card, + CardHeader, + CardTitle, + CardDescription, +} from "@/components/ui/card"; +import { EditProfileForm } from "@/components/edit-profile-form"; + +// This is a Server Component to fetch initial data +export default async function EditProfilePage() { + const token = (await cookies()).get("auth_token")?.value; + + if (!token) { + redirect("/login"); + } + + const me = await getMe(token).catch(() => null); + + if (!me) { + redirect("/login"); + } + + return ( +
+ + + Edit Profile + + Update your public profile information. + + + + +
+ ); +} diff --git a/thoughts-frontend/app/users/[username]/page.tsx b/thoughts-frontend/app/users/[username]/page.tsx index 7d6b675..74219a4 100644 --- a/thoughts-frontend/app/users/[username]/page.tsx +++ b/thoughts-frontend/app/users/[username]/page.tsx @@ -1,4 +1,4 @@ -import { getMe, getUserProfile, getUserThoughts } from "@/lib/api"; +import { getMe, getUserProfile, getUserThoughts, Me } from "@/lib/api"; import { UserAvatar } from "@/components/user-avatar"; import { ThoughtCard } from "@/components/thought-card"; import { Calendar } from "lucide-react"; @@ -35,7 +35,7 @@ export default async function ProfilePage({ params }: ProfilePageProps) { const user = userResult.value; const thoughts = thoughtsResult.status === "fulfilled" ? thoughtsResult.value.thoughts : []; - const me = meResult.status === "fulfilled" ? meResult.value : null; + const me = meResult.status === "fulfilled" ? (meResult.value as Me) : null; // *** SIMPLIFIED LOGIC *** // The follow status is now directly available from the `me` object. @@ -104,6 +104,7 @@ export default async function ProfilePage({ params }: ProfilePageProps) { key={thought.id} thought={thought} author={{ username: user.username, avatarUrl: user.avatarUrl }} + currentUser={me || null} /> ))} {thoughts.length === 0 && ( diff --git a/thoughts-frontend/components/edit-profile-form.tsx b/thoughts-frontend/components/edit-profile-form.tsx new file mode 100644 index 0000000..d38a55e --- /dev/null +++ b/thoughts-frontend/components/edit-profile-form.tsx @@ -0,0 +1,172 @@ +"use client"; + +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; +import { useRouter } from "next/navigation"; +import { useAuth } from "@/hooks/use-auth"; +import { Me, UpdateProfileSchema, updateProfile } from "@/lib/api"; +import { toast } from "sonner"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardFooter } from "@/components/ui/card"; +import { + Form, + FormField, + FormItem, + FormLabel, + FormControl, + FormMessage, + FormDescription, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { Textarea } from "@/components/ui/textarea"; + +interface EditProfileFormProps { + currentUser: Me; +} + +export function EditProfileForm({ currentUser }: EditProfileFormProps) { + const router = useRouter(); + const { token } = useAuth(); + + const form = useForm>({ + resolver: zodResolver(UpdateProfileSchema), + defaultValues: { + displayName: currentUser.displayName ?? undefined, + bio: currentUser.bio ?? undefined, + avatarUrl: currentUser.avatarUrl ?? undefined, + headerUrl: currentUser.headerUrl ?? undefined, + customCss: currentUser.customCss ?? undefined, + topFriends: currentUser.topFriends ?? [], + }, + }); + + async function onSubmit(values: z.infer) { + if (!token) return; + toast.info("Updating your profile..."); + try { + await updateProfile(values, token); + toast.success("Profile updated successfully!"); + // Redirect to the profile page to see the changes + router.push(`/users/${currentUser.username}`); + router.refresh(); // Ensure fresh data is loaded + } catch (err) { + toast.error("Failed to update profile."); + } + } + + return ( +
+ + + + ( + + Display Name + + + + + + )} + /> + ( + + Bio + +