mirror of https://github.com/waku-org/js-waku.git
Only add new listeners when waku is initialised
This commit is contained in:
parent
9c65e590c4
commit
f4663ab247
|
@ -46,15 +46,16 @@ const themes = {
|
|||
export const ChatContentTopic = 'dingpu';
|
||||
|
||||
export default function App() {
|
||||
let [stateMessages, setMessages] = useState<ChatMessage[]>([]);
|
||||
let [newMessages, setNewMessages] = useState<ChatMessage[]>([]);
|
||||
let [archivedMessages, setArchivedMessages] = useState<ChatMessage[]>([]);
|
||||
let [stateWaku, setWaku] = useState<Waku | undefined>(undefined);
|
||||
let [nick, setNick] = useState<string>(generate());
|
||||
|
||||
useEffect(() => {
|
||||
const handleNewMessages = (event: { data: Uint8Array }) => {
|
||||
const handleRelayMessage = (event: { data: Uint8Array }) => {
|
||||
const chatMsg = decodeWakuMessage(event.data);
|
||||
if (chatMsg) {
|
||||
copyAppendReplace([chatMsg], stateMessages, setMessages);
|
||||
setNewMessages([chatMsg]);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -78,7 +79,7 @@ export default function App() {
|
|||
.map((wakuChatMessage) =>
|
||||
ChatMessage.fromWakuChatMessage(wakuChatMessage)
|
||||
);
|
||||
copyMergeUniqueReplace(messages, stateMessages, setMessages);
|
||||
setArchivedMessages(messages);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -88,7 +89,7 @@ export default function App() {
|
|||
.then(() => console.log('Waku init done'))
|
||||
.catch((e) => console.log('Waku init failed ', e));
|
||||
} else {
|
||||
stateWaku.libp2p.pubsub.on(RelayDefaultTopic, handleNewMessages);
|
||||
stateWaku.libp2p.pubsub.on(RelayDefaultTopic, handleRelayMessage);
|
||||
|
||||
stateWaku.libp2p.peerStore.on(
|
||||
'change:protocols',
|
||||
|
@ -99,7 +100,7 @@ export default function App() {
|
|||
return () => {
|
||||
stateWaku?.libp2p.pubsub.removeListener(
|
||||
RelayDefaultTopic,
|
||||
handleNewMessages
|
||||
handleRelayMessage
|
||||
);
|
||||
stateWaku?.libp2p.peerStore.removeListener(
|
||||
'change:protocols',
|
||||
|
@ -107,7 +108,7 @@ export default function App() {
|
|||
);
|
||||
};
|
||||
}
|
||||
}, [stateWaku, stateMessages]);
|
||||
}, [stateWaku]);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -118,7 +119,8 @@ export default function App() {
|
|||
<ThemeProvider theme={themes}>
|
||||
<Room
|
||||
nick={nick}
|
||||
lines={stateMessages}
|
||||
newMessages={newMessages}
|
||||
archivedMessages={archivedMessages}
|
||||
commandHandler={(input: string) => {
|
||||
const { command, response } = handleCommand(
|
||||
input,
|
||||
|
@ -128,7 +130,7 @@ export default function App() {
|
|||
const commandMessages = response.map((msg) => {
|
||||
return new ChatMessage(new Date(), new Date(), command, msg);
|
||||
});
|
||||
copyAppendReplace(commandMessages, stateMessages, setMessages);
|
||||
setNewMessages(commandMessages);
|
||||
}}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
|
@ -170,35 +172,3 @@ function decodeWakuMessage(data: Uint8Array): null | ChatMessage {
|
|||
WakuChatMessage.decode(wakuMsg.payload)
|
||||
);
|
||||
}
|
||||
|
||||
function copyAppendReplace<T>(
|
||||
newValues: Array<T>,
|
||||
currentValues: Array<T>,
|
||||
setter: (val: Array<T>) => void
|
||||
) {
|
||||
const copy = currentValues.slice();
|
||||
setter(copy.concat(newValues));
|
||||
}
|
||||
|
||||
function copyMergeUniqueReplace(
|
||||
newValues: ChatMessage[],
|
||||
currentValues: ChatMessage[],
|
||||
setter: (val: ChatMessage[]) => void
|
||||
) {
|
||||
const copy = currentValues.slice();
|
||||
newValues.forEach((msg) => {
|
||||
if (!copy.find(isEqual.bind({}, msg))) {
|
||||
copy.push(msg);
|
||||
}
|
||||
});
|
||||
copy.sort((a, b) => a.sentTimestamp.valueOf() - b.sentTimestamp.valueOf());
|
||||
setter(copy);
|
||||
}
|
||||
|
||||
function isEqual(lhs: ChatMessage, rhs: ChatMessage): boolean {
|
||||
return (
|
||||
lhs.nick === rhs.nick &&
|
||||
lhs.message === rhs.message &&
|
||||
lhs.sentTimestamp.toString() === rhs.sentTimestamp.toString()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useEffect, useRef } from 'react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { ChatMessage } from './ChatMessage';
|
||||
import {
|
||||
Message,
|
||||
|
@ -8,18 +8,40 @@ import {
|
|||
} from '@livechat/ui-kit';
|
||||
|
||||
interface Props {
|
||||
messages: ChatMessage[];
|
||||
archivedMessages: ChatMessage[];
|
||||
newMessages: ChatMessage[];
|
||||
}
|
||||
|
||||
export default function ChatList(props: Props) {
|
||||
const messages = props.messages;
|
||||
const [messages, setMessages] = useState<ChatMessage[]>([]);
|
||||
let updatedMessages;
|
||||
|
||||
const messagesGroupedBySender = groupMessagesBySender(props.messages).map(
|
||||
if (IsThereNewMessages(props.newMessages, messages)) {
|
||||
updatedMessages = messages.slice().concat(props.newMessages);
|
||||
if (IsThereNewMessages(props.archivedMessages, updatedMessages)) {
|
||||
updatedMessages = copyMergeUniqueReplace(
|
||||
props.archivedMessages,
|
||||
updatedMessages
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (IsThereNewMessages(props.archivedMessages, messages)) {
|
||||
updatedMessages = copyMergeUniqueReplace(
|
||||
props.archivedMessages,
|
||||
messages
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (updatedMessages) {
|
||||
setMessages(updatedMessages);
|
||||
}
|
||||
|
||||
const messagesGroupedBySender = groupMessagesBySender(messages).map(
|
||||
(currentMessageGroup) => (
|
||||
<MessageGroup onlyFirstWithMeta>
|
||||
{currentMessageGroup.map((currentMessage) => (
|
||||
<Message
|
||||
// We assume that the same user is not sending two messages in the same second
|
||||
key={
|
||||
currentMessage.receivedTimestampMs.valueOf() +
|
||||
currentMessage.nick +
|
||||
|
@ -38,7 +60,7 @@ export default function ChatList(props: Props) {
|
|||
return (
|
||||
<MessageList active containScrollInSubtree>
|
||||
{messagesGroupedBySender}
|
||||
<AlwaysScrollToBottom messages={messages} />
|
||||
<AlwaysScrollToBottom newMessages={props.newMessages} />
|
||||
</MessageList>
|
||||
);
|
||||
}
|
||||
|
@ -71,14 +93,48 @@ function formatDisplayDate(message: ChatMessage): string {
|
|||
});
|
||||
}
|
||||
|
||||
const AlwaysScrollToBottom = (props: Props) => {
|
||||
const AlwaysScrollToBottom = (props: { newMessages: ChatMessage[] }) => {
|
||||
const elementRef = useRef<HTMLDivElement>();
|
||||
|
||||
useEffect(() => {
|
||||
// @ts-ignore
|
||||
elementRef.current.scrollIntoView();
|
||||
}, [props.messages]);
|
||||
}, [props.newMessages]);
|
||||
|
||||
// @ts-ignore
|
||||
return <div ref={elementRef} />;
|
||||
};
|
||||
|
||||
function IsThereNewMessages(
|
||||
newValues: ChatMessage[],
|
||||
currentValues: ChatMessage[]
|
||||
): boolean {
|
||||
if (newValues.length === 0) return false;
|
||||
if (currentValues.length === 0) return true;
|
||||
|
||||
return !newValues.find((newMsg) =>
|
||||
currentValues.find(isEqual.bind({}, newMsg))
|
||||
);
|
||||
}
|
||||
|
||||
function copyMergeUniqueReplace(
|
||||
newValues: ChatMessage[],
|
||||
currentValues: ChatMessage[]
|
||||
) {
|
||||
const copy = currentValues.slice();
|
||||
newValues.forEach((msg) => {
|
||||
if (!copy.find(isEqual.bind({}, msg))) {
|
||||
copy.push(msg);
|
||||
}
|
||||
});
|
||||
copy.sort((a, b) => a.sentTimestamp.valueOf() - b.sentTimestamp.valueOf());
|
||||
return copy;
|
||||
}
|
||||
|
||||
function isEqual(lhs: ChatMessage, rhs: ChatMessage): boolean {
|
||||
return (
|
||||
lhs.nick === rhs.nick &&
|
||||
lhs.message === rhs.message &&
|
||||
lhs.sentTimestamp.toString() === rhs.sentTimestamp.toString()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -10,8 +10,7 @@ import {
|
|||
} from '@livechat/ui-kit';
|
||||
|
||||
interface Props {
|
||||
messageHandler: (msg: string) => void;
|
||||
sendMessage: (() => Promise<void>) | undefined;
|
||||
sendMessage: ((msg: string) => Promise<void>) | undefined;
|
||||
}
|
||||
|
||||
export default function MessageInput(props: Props) {
|
||||
|
@ -20,14 +19,13 @@ export default function MessageInput(props: Props) {
|
|||
|
||||
const sendMessage = async () => {
|
||||
if (props.sendMessage) {
|
||||
await props.sendMessage();
|
||||
await props.sendMessage(inputText);
|
||||
setInputText('');
|
||||
}
|
||||
};
|
||||
|
||||
const messageHandler = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
setInputText(event.target.value);
|
||||
props.messageHandler(event.target.value);
|
||||
};
|
||||
|
||||
const keyPressHandler = async (event: KeyboardEvent<HTMLInputElement>) => {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { useState } from 'react';
|
||||
import { ChatMessage } from './ChatMessage';
|
||||
import { ChatMessage as WakuChatMessage } from 'waku/chat_message';
|
||||
import { WakuMessage } from 'waku/waku_message';
|
||||
|
@ -9,13 +8,13 @@ import { useWaku } from './WakuContext';
|
|||
import { TitleBar } from '@livechat/ui-kit';
|
||||
|
||||
interface Props {
|
||||
lines: ChatMessage[];
|
||||
newMessages: ChatMessage[];
|
||||
archivedMessages: ChatMessage[];
|
||||
commandHandler: (cmd: string) => void;
|
||||
nick: string;
|
||||
}
|
||||
|
||||
export default function Room(props: Props) {
|
||||
let [messageToSend, setMessageToSend] = useState<string>('');
|
||||
const { waku } = useWaku();
|
||||
|
||||
return (
|
||||
|
@ -24,12 +23,14 @@ export default function Room(props: Props) {
|
|||
style={{ height: '98vh', display: 'flex', flexDirection: 'column' }}
|
||||
>
|
||||
<TitleBar title="Waku v2 chat app" />
|
||||
<ChatList messages={props.lines} />
|
||||
<ChatList
|
||||
newMessages={props.newMessages}
|
||||
archivedMessages={props.archivedMessages}
|
||||
/>
|
||||
<MessageInput
|
||||
messageHandler={setMessageToSend}
|
||||
sendMessage={
|
||||
waku
|
||||
? async () => {
|
||||
? async (messageToSend) => {
|
||||
return handleMessage(
|
||||
messageToSend,
|
||||
props.nick,
|
||||
|
|
Loading…
Reference in New Issue