import Input from "@tensamin/markdown/input"; import { Avatar, AvatarFallback, AvatarImage, Card, CardHeader, Popover, PopoverContent, PopoverTrigger, Skeleton, } from "@tensamin/ui"; import { useStorage } from "@tensamin/storage/context"; import React, { useEffect, useState, useRef } from "react"; import { Button } from "@tensamin/ui"; import { Plus, Laugh, FileVideo, Forward, X } from "lucide-react"; import { useChat, useReplyMessage } from "../context"; import { useMTP } from "@tensamin/mtp"; import { log, toast } from "@tensamin/shared/log"; import { cn, useIsMobile } from "@tensamin/ui"; import { encryptChatText } from "@tensamin/crypto/chatSecret"; import { useSession } from "@tensamin/storage/session"; import GifPicker from "./gifPicker"; import Wrapper from "@tensamin/user/wrapper"; import Text from "@tensamin/markdown/text"; export default function InputComponent({ value, setValue, }: { value: string; setValue: (value: string) => void; }) { const [invertEnterBehavior, setInvertEnterBehavior] = useState(false); const { send } = useMTP(); const { addLiveMessage, chatSecret, userId, inputBoxRef, replyTo, setReplyTo, } = useChat(); const { load, save } = useStorage(); const { moveUserIdToTop } = useSession(); const gifPopoverRef = useRef(null); const [gifPopoverOpen, setGifPopoverOpen] = useState(false); const [gifPopoverSize, setGifPopoverSize] = useState<{ width: number; height: number; }>(); useEffect(() => { void load("settings.reverse_enter_behavior").then((shouldInvert) => { setInvertEnterBehavior(shouldInvert); }); }, [load]); useEffect(() => { void load("chat_picker_size").then((size) => { if (size) { setGifPopoverSize(size); } }); }, [load]); async function handleSubmit(content = value, preserveContent = false) { if (content.trim() === "") return; const time = new Date().getTime(); const currentValue = content; if (!Number.isSafeInteger(userId) || userId <= 0) { toast("error", "No conversation selected"); return; } if (!chatSecret) { toast("error", "Still getting chat secret..."); return; } log(3, "chat", "purple", "Message send init, adding live message ..."); const reference = addLiveMessage({ NotEncrypted: true, SendTime: time, Content: currentValue, SenderId: ownId, MessageState: "awaiting", ...(replyTo && { ReplyId: replyTo }), }); log(3, "chat", "purple", "Live message added, encrypting..."); const encryptedContent = await encryptChatText( chatSecret, currentValue, ).catch((err) => { toast("error", "Failed to encrypt message", String(err)); reference.setFailed(true); }); if (!encryptedContent) return; log(3, "chat", "purple", "Content encrypted, sending message..."); send("MessageSend", { Content: encryptedContent, ReceiverId: userId, SendTime: time, }).catch((e) => { log(0, "Chat", "red", "Failed to send message", e, { ReceiverId: userId, SendTime: time, }); reference.setFailed(true); toast("error", "Failed to send message"); }); if (replyTo) { setReplyTo(undefined); } log(3, "chat", "purple", "Message sent"); moveUserIdToTop(userId); if (!preserveContent) { setValue(""); } } const isMobile = useIsMobile(); function handleGifPopoverResizeStart( event: React.PointerEvent, ) { const popover = gifPopoverRef.current; if (!popover) return; event.preventDefault(); event.stopPropagation(); const rect = popover.getBoundingClientRect(); const startX = event.clientX; const startY = event.clientY; const startWidth = rect.width; const startHeight = rect.height; const minSize = 40; const maxSize = 720; function clampSize(size: number) { return Math.min(Math.max(size, minSize), maxSize); } function handlePointerMove(moveEvent: PointerEvent) { const nextSize = { width: clampSize(startWidth + startX - moveEvent.clientX), height: clampSize(startHeight + startY - moveEvent.clientY), }; setGifPopoverSize(nextSize); } function handlePointerUp() { const popover = gifPopoverRef.current; if (popover) { const rect = popover.getBoundingClientRect(); void save("chat_picker_size", { width: clampSize(rect.width), height: clampSize(rect.height), }); } window.removeEventListener("pointermove", handlePointerMove); window.removeEventListener("pointerup", handlePointerUp); } window.addEventListener("pointermove", handlePointerMove); window.addEventListener("pointerup", handlePointerUp); } const { ownId, replyMessage, replyUserId } = useReplyMessage(); return (
{replyTo !== undefined && (
{replyMessage ? ( <> } component={(user) => ( {user.Display.slice(2, 0).toUpperCase()} )} />
) : ( <> )}
)}

Files list

} /> event.stopPropagation()} onWheelCapture={(event) => event.stopPropagation()} style={{ ...gifPopoverSize, maxHeight: gifPopoverSize?.height, }} >
{ void handleSubmit(url, true); setGifPopoverOpen(false); }} />
); }