Files
diplom-frontend/app/components/message-box.tsx
2025-05-20 04:16:03 +03:00

103 lines
4.1 KiB
TypeScript

import { Plus, Send, Trash } from "lucide-react"
import React from "react"
import { sendMessage } from "~/lib/api/client/channel"
import { uploadFiles } from "~/lib/api/client/file"
import TextBox from "./custom-ui/text-box"
import { Button } from "./ui/button"
export interface MessageBoxProps {
channelId: string
}
export default function MessageBox(
{ channelId }: MessageBoxProps
) {
const [text, setText] = React.useState("")
const [attachments, setAttachments] = React.useState<File[]>([])
const fileInputRef = React.useRef<HTMLInputElement>(null)
const onSendMessage = async () => {
const content = text.trim()
if (!content && !attachments.length)
return
const uploadedAttachments = await uploadFiles(attachments)
await sendMessage(channelId, text, uploadedAttachments)
setText("")
setAttachments([])
}
const addAttachment = async () => {
if (!fileInputRef.current)
return
fileInputRef.current.click()
}
const onFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const files = Array.from(e.target.files || [])
const newAttachments = [...attachments, ...files]
setAttachments(newAttachments.slice(0, 10))
if (!fileInputRef.current)
return
fileInputRef.current.value = ""
}
React.useEffect(() => {
setText("")
setAttachments([])
}, [channelId])
return (
<div className="p-2">
<div className="max-h-1/2 w-full max-w-full grid items-center gap-x-2 outline-none py-4 px-2 rounded-xl no-scrollbar bg-background border border-input focus-within:ring-2 focus-within:ring-ring focus-within:border-ring"
style={{ gridTemplateColumns: "auto 1fr auto", gridTemplateRows: "1fr auto" }}>
<div className="row-start-1 col-start-1 row-span-2 col-span-1 h-full">
<Button size="icon" variant="ghost" onClick={addAttachment} disabled={attachments.length >= 10}>
<Plus />
</Button>
<input type="file" multiple className="hidden" ref={fileInputRef} onChange={onFileChange} />
</div>
<div className="flex-1 row-start-1 col-start-2 row-span-1 col-span-1">
<TextBox value={text}
wrapperClassName="contain-inline-size"
onChange={setText}
placeholder="Type your message here..."
aria-label="Message input">
</TextBox>
</div>
<div className="flex-1 row-start-2 col-start-2 row-span-1 col-span-1 overflow-y-auto max-h-40">
<div className={`${attachments.length > 0 ? "pt-2" : "hidden"}`}>
<div className="flex flex-col gap-2">
{
attachments.map((file, i) => (
<div key={i} className="flex items-center gap-2 wrap-anywhere rounded-xl border border-input bg-background p-2">
<div className="flex-1">
{file.name}
</div>
<div>
<Button size="icon" variant="destructive" onClick={() => setAttachments(attachments.filter((_, j) => i !== j))}>
<Trash />
</Button>
</div>
</div>
))
}
</div>
</div>
</div>
<div className="row-start-1 col-start-3 row-span-2 col-span-1 h-full">
<Button size="icon" onClick={onSendMessage}>
<Send />
</Button>
</div>
</div>
</div>
)
}