const componentOwnerId = props.componentOwnerId; const curbApi = props.curbApi; const activeChat = props.activeChat; const ChatContainer = styled.div` background-color: #0e0e10; padding-left: 4px; height: calc(100vh - 169px); @media (max-width: 1024px) { display: flex; flex-direction: column; height: 100%; } `; const pollMessages = (activeChat) => { const interval = setInterval(() => { curbApi .fetchMessages({ chat: activeChat }) .then((receivedMessages) => { if(messages !== receivedMessages) { setMessages(receivedMessages); } }) .catch((err) => console.log("Error fetching messages", err)); }, 200); return () => clearInterval(interval); }; const [messages, setMessages] = useState([]); const [openThreadId, setOpenThreadId] = useState(undefined); useEffect(() => { if (!activeChat) { return; } setOpenThreadId(undefined); setMessages([]); const stopPolling = pollMessages(activeChat); return () => { stopPolling(); }; }, [activeChat]); const readMessage = useCallback( (messageId) => { if (!messageId) { return; } return curbApi.readMessage({ chat: activeChat, messageId }); }, [activeChat, curbApi] ); const handleMessageSent = useCallback( (text, img, uploadedFile) => { let messageText = img ? `${text}$?$https://ipfs.near.social/ipfs/${img.cid}` : text; if (uploadedFile && uploadedFile.file.cid) { messageText = `${messageText}@?$@https://ipfs.near.social/ipfs/${uploadedFile.file.cid}?fileName=${uploadedFile.file.name}`; } // Temporal message removed for now because of refetching speed of 200ms // const temporalMessage = { // id: Date.now(), // we need to generate a unique id for the message in the client // nonce: Date.now(), // just mocking a nonce here, probably can be removed from the temporal message // reactions: {}, // empty reactions as it's a new message // sender: context.accountId, // the sender is the current user // text: messageText, // thread: [], // No thread as it's a new message // timestamp: Date.now(), // isTemporal: true, // marking the message as temporal // }; // if (!openThreadId) { // setMessages(messages.concat(temporalMessage)); // } else { // const messageIndex = messages.findIndex( // (message) => message.id === openThreadId // ); // setMessages( // messages // .slice(0, messageIndex) // .concat([ // { // ...messages[messageIndex], // thread: // messages[messageIndex].thread.concat(temporalMessage), // }, // ]) // .concat(messages.slice(messageIndex + 1)) // ); // } curbApi.sendMessage({ message: text, chat: activeChat, img, file: uploadedFile, threadId: openThreadId, }); }, [activeChat, curbApi, openThreadId, messages] ); return ( <ChatContainer> <Widget src={`${componentOwnerId}/widget/Calimero.Curb.Chat.ChatDisplay`} props={{ componentOwnerId, messages, readMessage, addMessageReaction: curbApi.toggleReaction, openThreadId, setOpenThreadId, }} /> <Widget src={`${componentOwnerId}/widget/Calimero.Curb.Chat.MessageInput`} props={{ componentOwnerId, selectedChat: activeChat.type === "channel" ? activeChat.name : activeChat.id, sendMessage: handleMessageSent, resetImage: props.resetImage, threadReply: openThreadId, }} /> </ChatContainer> );