"use client"; import { useState } from "react"; import { SmilePlus, MessageSquare, Download, Loader2 } from "lucide-react"; import { cn } from "@/lib/utils"; import { UserAvatar } from "./UserAvatar"; import { AuthImage } from "./AuthImage"; import type { Message } from "@/hooks/useMessenger"; import { useAddReaction } from "@/hooks/useMessenger"; import { toast } from "sonner"; const QUICK_EMOJIS = ["\u{1F44D}", "\u{2764}\u{FE0F}", "\u{1F602}", "\u{1F44F}", "\u{1F64F}", "\u{1F525}"]; interface MessageItemProps { message: Message; isOwn: boolean; showAvatar: boolean; isLastInGroup: boolean; } export function MessageItem({ message, isOwn, showAvatar, isLastInGroup }: MessageItemProps) { const [showActions, setShowActions] = useState(false); const [showEmojiPicker, setShowEmojiPicker] = useState(false); const [hovering, setHovering] = useState(false); const [downloading, setDownloading] = useState(false); const addReaction = useAddReaction(); if (message.isDeleted) { return (
{showAvatar && !isOwn ? ( ) : (
)}
삭제된 메시지입니다
); } const time = new Date(message.createdAt).toLocaleTimeString("ko-KR", { hour: "2-digit", minute: "2-digit", }); // Time element — sibling of bubble column in the outer flex row // isOwn: appears left of bubble (flex-row-reverse puts it visually left) // !isOwn: appears right of bubble const timeEl = ( {time} ); return ( // DOM order: [avatar, bubble column, timeEl] // isOwn flex-row-reverse → visual: [timeEl, bubble column, avatar] // !isOwn normal → visual: [avatar, bubble column, timeEl]
{/* avatar */} {!isOwn ? ( showAvatar ? (
) : (
) ) : (
)} {/* bubble column — direct flex child: max-w-[65%] resolves against full chat panel width */}
{ setShowActions(true); setHovering(true); }} onMouseLeave={() => { setShowActions(false); setShowEmojiPicker(false); setHovering(false); }} > {showAvatar && !isOwn && ( {message.senderName} )} {/* inline-block: sizes to content but constrained by parent max-w-[65%] */}
{message.type === "file" && message.fileMimeType?.startsWith("image/") && message.fileUrl ? ( ) : (
{message.type === "file" && message.fileUrl ? ( ) : ( {message.content} )}
)} {showActions && (
)} {showEmojiPicker && (
{QUICK_EMOJIS.map((emoji) => ( ))}
)}
{message.reactions.length > 0 && (
{message.reactions.map((r) => ( ))}
)}
{/* time — direct flex child, sibling of bubble column */} {timeEl}
); }