88 lines
2.8 KiB
React
88 lines
2.8 KiB
React
import { useState } from 'react'
|
|
import { useApp } from '../context/AppContext'
|
|
import { colorToCss } from '../utils/color'
|
|
import { connectionStatus } from '../utils/connection'
|
|
import MessageList from './MessageList'
|
|
import MessageInput from './MessageInput'
|
|
|
|
export default function ChatArea() {
|
|
const { state, userId } = useApp()
|
|
const conn = state.connections.find(c => c.id === state.selectedId)
|
|
const [pendingFile, setPendingFile] = useState(null)
|
|
const [dragCount, setDragCount] = useState(0)
|
|
const isDragging = dragCount > 0
|
|
|
|
function onDragEnter(e) {
|
|
if (Array.from(e.dataTransfer?.types ?? []).includes('Files')) {
|
|
setDragCount(c => c + 1)
|
|
}
|
|
}
|
|
function onDragLeave() {
|
|
setDragCount(c => Math.max(0, c - 1))
|
|
}
|
|
function onDragOver(e) {
|
|
if (Array.from(e.dataTransfer?.types ?? []).includes('Files')) {
|
|
e.preventDefault()
|
|
}
|
|
}
|
|
function onDrop(e) {
|
|
e.preventDefault()
|
|
setDragCount(0)
|
|
const file = e.dataTransfer?.files?.[0]
|
|
if (file && state.selectedId) setPendingFile(file)
|
|
}
|
|
|
|
let header = null
|
|
if (conn) {
|
|
const otherId = conn.requestorId === userId ? conn.recipientId : conn.requestorId
|
|
const other = state.userMap[otherId]
|
|
const status = connectionStatus(conn, userId)
|
|
header = (
|
|
<div className="flex items-center gap-3 px-4 py-3 border-b border-gray-700/60 shrink-0">
|
|
<div
|
|
className="w-8 h-8 rounded-full flex items-center justify-center text-white text-sm font-semibold shrink-0"
|
|
style={{ backgroundColor: colorToCss(other?.color) }}
|
|
>
|
|
{other?.name?.[0]?.toUpperCase() ?? '?'}
|
|
</div>
|
|
<div>
|
|
<p className="text-sm font-semibold text-white">{other?.name ?? '…'}</p>
|
|
{other?.pronouns && (
|
|
<p className="text-xs text-gray-500">{other.pronouns}</p>
|
|
)}
|
|
</div>
|
|
{status && (
|
|
<span className={`ml-auto text-xs ${status.cls}`}>● {status.label}</span>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div
|
|
className="flex-1 flex flex-col bg-gray-800 min-w-0 relative"
|
|
onDragEnter={onDragEnter}
|
|
onDragLeave={onDragLeave}
|
|
onDragOver={onDragOver}
|
|
onDrop={onDrop}
|
|
>
|
|
{header}
|
|
{state.selectedId ? (
|
|
<>
|
|
<MessageList />
|
|
<MessageInput pendingFile={pendingFile} setPendingFile={setPendingFile} />
|
|
</>
|
|
) : (
|
|
<div className="flex-1 flex items-center justify-center text-gray-600 text-sm">
|
|
Select a conversation
|
|
</div>
|
|
)}
|
|
{isDragging && state.selectedId && (
|
|
<div className="absolute inset-0 z-30 flex items-center justify-center bg-blue-500/20 border-2 border-dashed border-blue-400 pointer-events-none">
|
|
<p className="text-blue-200 text-sm font-semibold">Drop file to attach</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|