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(messages => { setMessages(messages); }) .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}`; } 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, ] ); 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> );