'use client'
import * as React from 'react'
import { cn } from '@/lib/utils'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
// Icons
const SendIcon = () => (
)
const EmojiIcon = () => (
)
const AttachIcon = () => (
)
// Typing indicator dots
function TypingIndicator({ className }: { className?: string }) {
return (
{[0, 1, 2].map((i) => (
))}
)
}
// Single message bubble
interface MessageProps {
content: string
sender: {
name: string
avatar?: string
initials: string
}
timestamp?: string
isOwn?: boolean
status?: 'sent' | 'delivered' | 'read'
reactions?: { emoji: string; count: number }[]
className?: string
}
function Message({
content,
sender,
timestamp,
isOwn = false,
status,
reactions,
className,
}: MessageProps) {
return (
{!isOwn && (
{sender.avatar ? (
) : null}
{sender.initials}
)}
{!isOwn && (
{sender.name}
)}
{content}
{reactions && reactions.length > 0 && (
{reactions.map((reaction, i) => (
{reaction.emoji} {reaction.count > 1 && reaction.count}
))}
)}
{(timestamp || status) && (
{timestamp && {timestamp}}
{isOwn && status && (
{status === 'sent' && '✓'}
{status === 'delivered' && '✓✓'}
{status === 'read' && '✓✓'}
)}
)}
)
}
// Chat container
interface ChatProps {
title?: string
subtitle?: string
messages?: MessageProps[]
className?: string
onSend?: (message: string) => void
showTyping?: boolean
}
function Chat({
title = 'Chat',
subtitle,
messages = [],
className,
onSend,
showTyping = false,
}: ChatProps) {
const [inputValue, setInputValue] = React.useState('')
const messagesEndRef = React.useRef(null)
const handleSend = () => {
if (inputValue.trim() && onSend) {
onSend(inputValue.trim())
setInputValue('')
}
}
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault()
handleSend()
}
}
return (
{/* Header */}
{title}
{subtitle && (
{subtitle}
)}
{/* Messages area */}
{messages.map((message, i) => (
))}
{showTyping &&
}
{/* Input area */}
)
}
// Presence indicator
interface PresenceProps {
status: 'online' | 'away' | 'busy' | 'offline'
label?: boolean
className?: string
}
function Presence({ status, label = false, className }: PresenceProps) {
const statusConfig = {
online: {
color: 'bg-success shadow-[0_0_8px_oklch(0.72_0.19_145_/_0.6)]',
text: 'Online',
},
away: {
color: 'bg-warning',
text: 'Away',
},
busy: {
color: 'bg-destructive',
text: 'Do not disturb',
},
offline: {
color: 'bg-muted-foreground',
text: 'Offline',
},
}
const config = statusConfig[status]
return (
{label && (
{config.text}
)}
)
}
export { Chat, Message, TypingIndicator, Presence }