|
|
|
@@ -19,6 +19,7 @@ export default function ChatWindow({ group, onBack, onGroupUpdated, onDirectMess
|
|
|
|
|
const [typing, setTyping] = useState([]);
|
|
|
|
|
const [iconGroupInfo, setIconGroupInfo] = useState('');
|
|
|
|
|
const [showInfo, setShowInfo] = useState(false);
|
|
|
|
|
const [replyTo, setReplyTo] = useState(null);
|
|
|
|
|
const [isMobile, setIsMobile] = useState(window.innerWidth < 768);
|
|
|
|
|
|
|
|
|
|
const messagesEndRef = useRef(null);
|
|
|
|
@@ -143,10 +144,16 @@ export default function ChatWindow({ group, onBack, onGroupUpdated, onDirectMess
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleSend = async ({ content, imageUrl, replyToId }) => {
|
|
|
|
|
if ((!content?.trim() && !imageUrl) || !group) return;
|
|
|
|
|
const handleSend = async ({ content, imageFile, linkPreview, emojiOnly }) => {
|
|
|
|
|
if ((!content?.trim() && !imageFile) || !group) return;
|
|
|
|
|
const replyToId = replyTo?.id || null;
|
|
|
|
|
setReplyTo(null);
|
|
|
|
|
try {
|
|
|
|
|
await api.sendMessage({ groupId: group.id, content: content?.trim() || '', imageUrl, replyToId });
|
|
|
|
|
if (imageFile) {
|
|
|
|
|
await api.uploadImage(group.id, imageFile, { replyToId, content: content?.trim() || '' });
|
|
|
|
|
} else {
|
|
|
|
|
await api.sendMessage(group.id, { content: content.trim(), replyToId, linkPreview, emojiOnly });
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
toast(e.message || 'Failed to send', 'error');
|
|
|
|
|
}
|
|
|
|
@@ -169,7 +176,7 @@ export default function ChatWindow({ group, onBack, onGroupUpdated, onDirectMess
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleReply = (msg) => {
|
|
|
|
|
window.dispatchEvent(new CustomEvent('jama:reply', { detail: msg }));
|
|
|
|
|
setReplyTo(msg);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleDirectMessage = (dmGroup) => {
|
|
|
|
@@ -199,6 +206,7 @@ export default function ChatWindow({ group, onBack, onGroupUpdated, onDirectMess
|
|
|
|
|
const isOnline = isDirect && group.peer_id && (onlineUserIds instanceof Set ? onlineUserIds.has(Number(group.peer_id)) : false);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<div className="chat-window">
|
|
|
|
|
{/* Header */}
|
|
|
|
|
<div className="chat-header">
|
|
|
|
@@ -292,8 +300,9 @@ export default function ChatWindow({ group, onBack, onGroupUpdated, onDirectMess
|
|
|
|
|
This channel is read-only
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<MessageInput group={group} currentUser={currentUser} onSend={handleSend} socket={socket} />
|
|
|
|
|
<MessageInput group={group} currentUser={currentUser} onSend={handleSend} socket={socket} replyTo={replyTo} onCancelReply={() => setReplyTo(null)} onTyping={() => {}} />
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
{showInfo && (
|
|
|
|
|
<GroupInfoModal
|
|
|
|
|
group={group}
|
|
|
|
@@ -302,6 +311,6 @@ export default function ChatWindow({ group, onBack, onGroupUpdated, onDirectMess
|
|
|
|
|
onBack={() => setShowInfo(false)}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|