import { ArrowRight, Image as ImageIcon, Loader2, Reply, SmilePlus, X } from "lucide-react"; import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover"; import { useRef, useState } from "react"; import EmojiPicker from "./EmojiPicker"; import type { MessageList } from "../../../src/api/types/models"; import { useAuthToken } from "../../hooks/use-root-data"; import { getApiBaseUrl } from "../../utils/api-config"; import { toast } from "../../hooks/use-toast"; const MAX_IMAGE_BYTES = 8 * 1024 * 1024; const ALLOWED_IMAGE_TYPES = ["image/jpeg", "image/jpg", "image/png", "image/webp", "image/heic", "image/heif"]; // Message input component // // `canSendImage` toggles the paperclip button — only team members (owner or // active staff of the thread's seller) can attach images. The buyer side // leaves it off so customers can only send text. const MessageInput = ({ onSend, onSendImage, canSendImage = false, replyToMessage, onCancelReply, messageText, setMessageText, isSendingMessage, setReplyToMessage, }: { onSend: (text: string) => void; onSendImage?: (imageUrl: string) => void; canSendImage?: boolean; replyToMessage: MessageList | undefined; onCancelReply: () => void; inputRef: React.RefObject; messageText: string; setMessageText: React.Dispatch>; isSendingMessage: boolean; setReplyToMessage: (message: MessageList | undefined) => void; }) => { const token = useAuthToken(); const apiBase = getApiBaseUrl(); const fileInputRef = useRef(null); const [isUploadingImage, setIsUploadingImage] = useState(false); const [caretPosition, setCaretPosition] = useState(null); // Track current textarea height const handleSend = () => { if (!messageText.trim() || isSendingMessage) return; onSend(messageText.trim()); }; // Handle emoji selection const handleSelectEmoji = (selectedEmoji: string) => { if (textareaRef.current) { // Get current cursor position const cursorPosition = caretPosition !== null ? caretPosition : textareaRef.current.selectionStart; // Insert emoji at cursor position const newText = messageText.substring(0, cursorPosition) + selectedEmoji + messageText.substring(cursorPosition); setMessageText(newText); // After state update, set cursor position after the inserted emoji setTimeout(() => { if (textareaRef.current) { const newPosition = cursorPosition + selectedEmoji.length; textareaRef.current.focus(); textareaRef.current.setSelectionRange(newPosition, newPosition); } }, 0); } else { // Fallback if ref not available setMessageText((prev) => prev + selectedEmoji); } }; // Store caret position on selection change const handleTextareaSelect = () => { if (textareaRef.current) { setCaretPosition(textareaRef.current.selectionStart); } }; // Auto-growing textarea ref const textareaRef = useRef(null); // Handle text change and update height const handleTextChange = (e: React.ChangeEvent) => { setMessageText(e.target.value); }; const handlePickImage = () => { if (!canSendImage || isUploadingImage) return; fileInputRef.current?.click(); }; const handleFileSelected = async ( e: React.ChangeEvent, ) => { const file = e.target.files?.[0]; // Reset the input so the same file can be re-picked after cancel. if (e.target) e.target.value = ""; if (!file || !canSendImage || !onSendImage) return; if (!ALLOWED_IMAGE_TYPES.includes(file.type)) { toast({ title: "فرمت پشتیبانی نمی‌شود", description: "فقط تصاویر JPG / PNG / WebP / HEIC مجاز است.", variant: "destructive", }); return; } if (file.size > MAX_IMAGE_BYTES) { toast({ title: "حجم زیاد", description: "حداکثر حجم تصویر ۸ مگابایت است.", variant: "destructive", }); return; } setIsUploadingImage(true); try { const form = new FormData(); form.append("file", file); form.append("usage", "chat"); const headers: Record = {}; if (token) headers["Authorization"] = `Bearer ${token}`; const res = await fetch(`${apiBase}/api/media/v1/upload/`, { method: "POST", headers, body: form, }); if (!res.ok) throw new Error(`upload failed: ${res.status}`); const data = await res.json(); const url: string | undefined = data.originalUrl || data.original_url; if (!url) throw new Error("no url in upload response"); onSendImage(url); } catch (err) { console.error("chat image upload failed:", err); toast({ title: "خطا در ارسال تصویر", description: "لطفاً دوباره تلاش کنید.", variant: "destructive", }); } finally { setIsUploadingImage(false); } }; return ( <> {/* Reply indicator */} {replyToMessage && (

در پاسخ به:

{replyToMessage.content}

)}
{replyToMessage && (
{replyToMessage.content}
)}
{canSendImage && ( <> )}