"use client" import { createContext, useContext, useTransition } from "react" import { useForm } from "react-hook-form" import { zodResolver } from "@hookform/resolvers/zod" import { z } from "zod" import { toast } from "sonner" import { useRouter } from "next/navigation" import { useTheme } from "next-themes" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Button } from "@/components/ui/button" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { Switch } from "@/components/ui/switch" import { Textarea } from "@/components/ui/textarea" import { updateProfile, type ProfileData } from "@/app/actions/profile" const ProfileFormContext = createContext<{ isPending: boolean } | null>(null) function useProfileForm() { const ctx = useContext(ProfileFormContext) if (!ctx) throw new Error("useProfileForm must be used within ProfileForm") return ctx } export function ProfileFormSubmitButton() { const { isPending } = useProfileForm() return ( {isPending ? "Saving..." : "Save Changes"} ) } const formSchema = z.object({ displayName: z.string().max(50, "Display name too long").optional(), firstName: z.string().max(50, "First name too long").optional(), lastName: z.string().max(50, "Last name too long").optional(), bio: z.string().max(500, "Bio too long").optional(), theme: z.enum(["system", "light", "dark"]), emailNotifications: z.boolean(), }) type FormData = z.infer function getInitials(name: string): string { const parts = name.split(" ").filter(Boolean) if (parts.length >= 2) { return (parts[0][0] + parts[1][0]).toUpperCase() } return name.slice(0, 2).toUpperCase() } interface ProfileFormProps { profile: ProfileData formId?: string children?: React.ReactNode } export function ProfileForm({ profile, formId = "profile-form", children }: ProfileFormProps) { const [isPending, startTransition] = useTransition() const router = useRouter() const { setTheme } = useTheme() const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { displayName: profile.displayName === profile.email.split("@")[0] ? "" : profile.displayName, firstName: profile.firstName ?? "", lastName: profile.lastName ?? "", bio: profile.bio ?? "", theme: profile.theme as "system" | "light" | "dark", emailNotifications: profile.emailNotifications, }, }) const onSubmit = (data: FormData) => { startTransition(async () => { const result = await updateProfile(profile.id, { displayName: data.displayName || undefined, firstName: data.firstName || undefined, lastName: data.lastName || undefined, bio: data.bio || undefined, theme: data.theme, emailNotifications: data.emailNotifications, }) if (result.success) { toast.success("Profile updated") router.refresh() } else { toast.error(result.error || "Failed to update profile") } }) } return ( {children} Avatar Your avatar is managed through your authentication provider {getInitials(profile.displayName)} {profile.displayName} {profile.email} Profile Information Update your display name and personal details Display Name {form.formState.errors.displayName && ( {form.formState.errors.displayName.message} )} First Name {form.formState.errors.firstName && ( {form.formState.errors.firstName.message} )} Last Name {form.formState.errors.lastName && ( {form.formState.errors.lastName.message} )} Bio {form.formState.errors.bio && ( {form.formState.errors.bio.message} )} Preferences Customize your experience Theme { form.setValue("theme", value as FormData["theme"]) setTheme(value) }} > System Light Dark Email Notifications Receive email updates about activity form.setValue("emailNotifications", checked) } className="data-[state=checked]:bg-primary" /> ) }
{profile.displayName}
{profile.email}
{form.formState.errors.displayName.message}
{form.formState.errors.firstName.message}
{form.formState.errors.lastName.message}
{form.formState.errors.bio.message}
Receive email updates about activity