"use client" import NewProjectModal from "@/components/dashboard/newProject" import ProjectCard from "@/components/dashboard/projectCard/" import { Button } from "@/components/ui/button" import { Card, CardContent, CardDescription, CardTitle, } from "@/components/ui/card" import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form" import { HoverCard, HoverCardContent, HoverCardTrigger, } from "@/components/ui/hover-card" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip" import { deleteSandbox, updateSandbox, updateUser } from "@/lib/actions" import { socialIcons } from "@/lib/data" import { editUserSchema, EditUserSchema } from "@/lib/schema" import { TIERS } from "@/lib/tiers" import { SandboxWithLiked, User, UserLink } from "@/lib/types" import { cn, parseSocialLink } from "@/lib/utils" import { useUser } from "@clerk/nextjs" import { zodResolver } from "@hookform/resolvers/zod" import { Edit, Globe, Heart, Info, Loader2, LucideIcon, Package2, PlusCircle, Sparkles, Trash2, X, } from "lucide-react" import { useRouter } from "next/navigation" import { Fragment, useCallback, useEffect, useMemo, useRef, useState, useTransition, } from "react" import { useFormState, useFormStatus } from "react-dom" import { useFieldArray, useForm } from "react-hook-form" import { toast } from "sonner" import Avatar from "../ui/avatar" import { Badge } from "../ui/badge" import { Input } from "../ui/input" import { Progress } from "../ui/progress" import { Textarea } from "../ui/textarea" // #region Profile Page export default function ProfilePage({ publicSandboxes, privateSandboxes, profileOwner, loggedInUser, }: { publicSandboxes: SandboxWithLiked[] privateSandboxes: SandboxWithLiked[] profileOwner: User loggedInUser: User | null }) { const isOwnProfile = profileOwner.id === loggedInUser?.id const sandboxes = useMemo(() => { const allSandboxes = isOwnProfile ? [...publicSandboxes, ...privateSandboxes] : publicSandboxes return allSandboxes }, [isOwnProfile, publicSandboxes, privateSandboxes]) return ( <>
) } // #endregion // #region Profile Card function ProfileCard({ name, username, avatarUrl, sandboxes, joinedDate, generations, isOwnProfile, bio, personalWebsite, socialLinks = [], tier, }: { name: string username: string avatarUrl: string | null bio: string | null personalWebsite: string | null socialLinks: UserLink[] sandboxes: SandboxWithLiked[] joinedDate: Date generations?: number isOwnProfile: boolean tier: string }) { const { user } = useUser() const [isEditing, setIsEditing] = useState(false) const joinedAt = useMemo(() => { const date = new Date(joinedDate).toLocaleDateString("en-US", { month: "long", year: "numeric", }) return `Joined ${date}` }, [joinedDate]) const toggleEdit = useCallback(() => { setIsEditing((s) => !s) }, []) const stats = useMemo(() => { const totalSandboxes = sandboxes.length const totalLikes = sandboxes.reduce( (sum, sandbox) => sum + sandbox.likeCount, 0 ) return { sandboxes: totalSandboxes === 1 ? "1 sandbox" : `${totalSandboxes} sandboxes`, likes: totalLikes === 1 ? "1 like" : `${totalLikes} likes`, } }, [sandboxes]) const showAddMoreInfoBanner = useMemo(() => { return !bio && !personalWebsite && (socialLinks?.length ?? 0) === 0 }, [personalWebsite, bio, socialLinks]) return ( {isOwnProfile && (

{showAddMoreInfoBanner ? "Add more information to your profile" : "Edit your profile"}

)} {isEditing ? ( ) : (
{name} {`@${username}`}
{typeof generations === "number" && (
)}
{bio &&

{bio}

} {(socialLinks.length > 0 || personalWebsite) && (
{personalWebsite && ( )} {socialLinks.map((link, index) => { const Icon = socialIcons[link.platform] return ( ) })}
)}

{joinedAt}

)}
) } function EditProfileForm(props: { name: string username: string avatarUrl: string | null bio: string | null personalWebsite: string | null socialLinks: UserLink[] toggleEdit: () => void }) { const router = useRouter() const { user } = useUser() const formRef = useRef(null) const [formState, formAction] = useFormState(updateUser, { message: "", }) const [isPending, startTransition] = useTransition() const { name, username, bio, personalWebsite, socialLinks, toggleEdit } = props const form = useForm({ resolver: zodResolver(editUserSchema), defaultValues: { oldUsername: username, id: user?.id, name, username, bio: bio ?? "", personalWebsite: personalWebsite ?? "", links: socialLinks.length > 0 ? socialLinks : [{ url: "", platform: "generic" }], ...(formState.fields ?? {}), }, }) const { fields, append, remove } = useFieldArray({ name: "links", control: form.control, }) useEffect(() => { const message = formState.message if (!Boolean(message)) return if ("error" in formState) { toast.error(formState.message) return } toast.success(formState.message as String) toggleEdit() if (formState?.newRoute) { router.replace(formState.newRoute) } }, [formState]) return (
{ evt.preventDefault() form.handleSubmit(() => { startTransition(() => { formAction(new FormData(formRef.current!)) }) })(evt) }} className="space-y-3 w-full" > ( Name )} /> ( User name
@
)} /> ( Bio