diff --git a/packages/react-chat-example/src/index.tsx b/packages/react-chat-example/src/index.tsx index 0f73f52f..f5d7b270 100644 --- a/packages/react-chat-example/src/index.tsx +++ b/packages/react-chat-example/src/index.tsx @@ -76,7 +76,7 @@ function DragDiv() { diff --git a/packages/react-chat/package.json b/packages/react-chat/package.json index 2ae7f317..a493f968 100644 --- a/packages/react-chat/package.json +++ b/packages/react-chat/package.json @@ -46,6 +46,7 @@ "dependencies": { "emoji-mart": "^3.0.1", "html-entities": "^2.3.2", + "js-sha3": "^0.8.0", "react": "^17.0.2", "react-dom": "^17.0.2", "react-is": "^17.0.2", diff --git a/packages/react-chat/src/components/Chat/ChatInput.tsx b/packages/react-chat/src/components/Chat/ChatInput.tsx index 9729db58..6533399e 100644 --- a/packages/react-chat/src/components/Chat/ChatInput.tsx +++ b/packages/react-chat/src/components/Chat/ChatInput.tsx @@ -108,7 +108,7 @@ export function ChatInput({ reply, setReply }: ChatInputProps) { e.preventDefault(); (e.target as HTMLDivElement).style.height = "40px"; setInputHeight(40); - sendMessage(content, imageUint); + sendMessage(content, imageUint, reply?.id); setImageUint(undefined); setClearComponent(""); if (inputRef.current) { diff --git a/packages/react-chat/src/components/Chat/ChatMessages.tsx b/packages/react-chat/src/components/Chat/ChatMessages.tsx index 0992a399..0c3fab7a 100644 --- a/packages/react-chat/src/components/Chat/ChatMessages.tsx +++ b/packages/react-chat/src/components/Chat/ChatMessages.tsx @@ -31,6 +31,7 @@ type ChatUiMessageProps = { setImage: (img: string) => void; setLink: (link: string) => void; setReply: (val: Reply | undefined) => void; + quote?: ChatMessage; }; function ChatUiMessage({ @@ -40,6 +41,7 @@ function ChatUiMessage({ setImage, setLink, setReply, + quote, }: ChatUiMessageProps) { const { contacts } = useMessengerContext(); const contact = useMemo( @@ -60,14 +62,14 @@ function ChatUiMessage({ )} - {message.quote && ( + {quote && ( {" "} - {message.quote.author} + {quote.sender} - {message.quote.content} + {quote.content} )} @@ -114,7 +116,11 @@ function ChatUiMessage({ - setReply({ sender: message.sender, content: message.content }) + setReply({ + sender: message.sender, + content: message.content, + id: message.id, + }) } > @@ -171,13 +177,14 @@ export function ChatMessages({ setReply }: ChatMessagesProps) { )} {shownMessages.map((message, idx) => ( msg.id == message?.responseTo)} /> ))} diff --git a/packages/react-chat/src/hooks/messenger/useMessenger.ts b/packages/react-chat/src/hooks/messenger/useMessenger.ts index 3e6fc9b7..e7dc191d 100644 --- a/packages/react-chat/src/hooks/messenger/useMessenger.ts +++ b/packages/react-chat/src/hooks/messenger/useMessenger.ts @@ -26,7 +26,8 @@ export type MessengerType = { messages: ChatMessage[]; sendMessage: ( messageText?: string | undefined, - image?: Uint8Array | undefined + image?: Uint8Array | undefined, + responseTo?: string ) => Promise; notifications: { [chatId: string]: number }; clearNotifications: (id: string) => void; @@ -199,7 +200,7 @@ export function useMessenger( }, [messenger, community]); const sendMessage = useCallback( - async (messageText?: string, image?: Uint8Array) => { + async (messageText?: string, image?: Uint8Array, responseTo?: string) => { let content; if (messageText) { content = { @@ -218,7 +219,7 @@ export function useMessenger( if (activeChannel.type === "group") { await groupChat?.sendMessage(activeChannel.id, content); } else { - await messenger?.sendMessage(activeChannel.id, content); + await messenger?.sendMessage(activeChannel.id, content, responseTo); } } }, diff --git a/packages/react-chat/src/hooks/useReply.ts b/packages/react-chat/src/hooks/useReply.ts index 8143355d..ec35980d 100644 --- a/packages/react-chat/src/hooks/useReply.ts +++ b/packages/react-chat/src/hooks/useReply.ts @@ -1,4 +1,5 @@ export type Reply = { sender: string; content: string; + id: string; }; diff --git a/packages/react-chat/src/models/ChatMessage.ts b/packages/react-chat/src/models/ChatMessage.ts index e2238f33..591eb468 100644 --- a/packages/react-chat/src/models/ChatMessage.ts +++ b/packages/react-chat/src/models/ChatMessage.ts @@ -1,3 +1,4 @@ +import { keccak256 } from "js-sha3"; import { ApplicationMetadataMessage, utils } from "status-communities/dist/cjs"; import { uintToImgUrl } from "../utils"; @@ -7,23 +8,22 @@ export class ChatMessage { date: Date; sender: string; image?: string; - quote?: { - author: string; - content: string; - }; + responseTo?: string; + id: string; constructor( content: string, date: Date, sender: string, image?: string, - quote?: { author: string; content: string } + responseTo?: string ) { this.content = content; this.date = date; this.sender = sender; this.image = image; - this.quote = quote; + this.responseTo = responseTo; + this.id = keccak256(date.getTime().toString() + content); } public static fromMetadataMessage( @@ -41,7 +41,13 @@ export class ChatMessage { image = uintToImgUrl(msg.chatMessage?.image.payload); } const sender = utils.bufToHex(msg.signer); - return new ChatMessage(content, date, sender, image); + return new ChatMessage( + content, + date, + sender, + image, + msg.chatMessage.responseTo + ); } else { return undefined; } diff --git a/packages/status-communities/src/chat.ts b/packages/status-communities/src/chat.ts index 8727fe32..6392f425 100644 --- a/packages/status-communities/src/chat.ts +++ b/packages/status-communities/src/chat.ts @@ -33,14 +33,15 @@ export class Chat { return idToContentTopic(this.id); } - public createMessage(content: Content): ChatMessage { + public createMessage(content: Content, responseTo?: string): ChatMessage { const { timestamp, clock } = this._nextClockAndTimestamp(); const message = ChatMessage.createMessage( clock, timestamp, this.id, - content + content, + responseTo ); this._updateClockFromMessage(message); diff --git a/packages/status-communities/src/messenger.ts b/packages/status-communities/src/messenger.ts index 618d8256..f0b07830 100644 --- a/packages/status-communities/src/messenger.ts +++ b/packages/status-communities/src/messenger.ts @@ -100,11 +100,15 @@ export class Messenger { /** * Sends a message on the given chat Id. */ - public async sendMessage(chatId: string, content: Content): Promise { + public async sendMessage( + chatId: string, + content: Content, + responseTo?: string + ): Promise { const chat = this.chatsById.get(chatId); if (!chat) throw `Failed to send message, chat not joined: ${chatId}`; - const chatMessage = chat.createMessage(content); + const chatMessage = chat.createMessage(content, responseTo); const appMetadataMessage = ApplicationMetadataMessage.create( chatMessage.encode(), diff --git a/packages/status-communities/src/wire/chat_message.ts b/packages/status-communities/src/wire/chat_message.ts index 01c3beaf..3dda0482 100644 --- a/packages/status-communities/src/wire/chat_message.ts +++ b/packages/status-communities/src/wire/chat_message.ts @@ -75,7 +75,8 @@ export class ChatMessage { clock: number, timestamp: number, chatId: string, - content: Content + content: Content, + responseTo?: string ): ChatMessage { let sticker, image, @@ -117,7 +118,7 @@ export class ChatMessage { timestamp, //ms? text, /** Id of the message that we are replying to */ - responseTo: "", + responseTo: responseTo ?? "", /** Ens name of the sender */ ensName: "", /** Public Key of the community (TBC) **/ diff --git a/yarn.lock b/yarn.lock index 78787d3b..f81653ca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -288,6 +288,7 @@ __metadata: emoji-mart: ^3.0.1 eslint: ^7.32.0 html-entities: ^2.3.2 + js-sha3: ^0.8.0 jsdom: ^16.7.0 jsdom-global: ^3.0.2 mocha: ^9.0.3