/** * @file components/ui/UserProfilePopover.tsx * @description User profile popover component displaying user details, email, and interactive options to message or add them as a friend. */ "use client"; import { useLayoutEffect, useRef, useState } from "react"; import { MessageSquare, UserPlus, Check, Clock, Loader2 } from "lucide-react"; import type { User } from "@/db/schema"; import { UserAvatar } from "../ui/UserAvatar"; import { ActionButton } from "./ActionButton"; /** Props for the UserProfilePopover component. */ interface UserProfilePopoverProps { user: User; currentUserId: string; triggerRef: React.RefObject; friendshipStatus?: string | null; onDirectMessage?: (userId: string) => void; onAddFriend?: (username: string) => Promise | void; } /** Popover component for displaying user info and quick actions. */ export function UserProfilePopover({ user, currentUserId, triggerRef, friendshipStatus, onDirectMessage, onAddFriend, }: UserProfilePopoverProps) { const popoverRef = useRef(null); const [coords, setCoords] = useState<{ top: number; left: number }>({ top: 0, left: 0, }); const [isVisible, setIsVisible] = useState(false); const [isLoading, setIsLoading] = useState(false); const [justSent, setJustSent] = useState(false); const isSelf = user.id === currentUserId; const isAlreadyFriend = friendshipStatus === "ACCEPTED"; const isPending = friendshipStatus === "PENDING" || justSent; const isButtonDisabled = isLoading || isAlreadyFriend || isPending; useLayoutEffect(() => { if (!triggerRef.current || !popoverRef.current) return; const triggerRect = triggerRef.current.getBoundingClientRect(); const popoverRect = popoverRef.current.getBoundingClientRect(); const viewportHeight = window.innerHeight; let top = triggerRect.bottom + 8; const left = triggerRect.left; if (top + popoverRect.height > viewportHeight - 16) { top = triggerRect.top - popoverRect.height - 8; } setCoords({ top, left }); setIsVisible(true); }, [triggerRef]); /** Handles sending a friend request asynchronously. */ const handleAddFriendClick = async () => { if (isButtonDisabled || !onAddFriend) return; setIsLoading(true); try { await onAddFriend(user.username); setJustSent(true); } catch (err) { console.error("Failed to add friend", err); } finally { setIsLoading(false); } }; return (

{user.username}

{user.status.toLowerCase()}

{!isSelf && (
onDirectMessage?.(user.id)} icon={MessageSquare} size="sm" className="flex-1" > Message
)}
); }