Improve use messenger (#18)

This commit is contained in:
Szymon Szlachtowicz 2021-09-29 15:05:43 +02:00 committed by GitHub
parent c9246acd1e
commit c07d912c39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 133 additions and 73 deletions

View File

@ -1,4 +1,4 @@
import React from "react"; import React, { useEffect } from "react";
import styled from "styled-components"; import styled from "styled-components";
import { ChannelData, channels } from "../helpers/channelsMock"; import { ChannelData, channels } from "../helpers/channelsMock";
@ -8,6 +8,8 @@ interface ChannelsProps {
theme: Theme; theme: Theme;
icon: string; icon: string;
name: string; name: string;
notifications: { [id: string]: number };
clearNotifications: (id: string) => void;
members: number; members: number;
setActiveChannel: (val: ChannelData) => void; setActiveChannel: (val: ChannelData) => void;
activeChannelId: number; activeChannelId: number;
@ -18,9 +20,20 @@ export function Channels({
icon, icon,
name, name,
members, members,
notifications,
setActiveChannel, setActiveChannel,
clearNotifications,
activeChannelId, activeChannelId,
}: ChannelsProps) { }: ChannelsProps) {
useEffect(() => {
const channel = channels.find((channel) => channel.id === activeChannelId);
if (channel) {
if (notifications[channel.name] > 0) {
clearNotifications(channel.name);
}
}
}, [notifications, activeChannelId]);
return ( return (
<ChannelsWrapper theme={theme}> <ChannelsWrapper theme={theme}>
<Community> <Community>
@ -37,6 +50,11 @@ export function Channels({
channel={channel} channel={channel}
theme={theme} theme={theme}
isActive={channel.id === activeChannelId} isActive={channel.id === activeChannelId}
notification={
notifications[channel.name] > 0
? notifications[channel.name]
: undefined
}
onClick={() => { onClick={() => {
setActiveChannel(channel); setActiveChannel(channel);
}} }}
@ -50,6 +68,7 @@ export function Channels({
interface ChannelProps { interface ChannelProps {
theme: Theme; theme: Theme;
channel: ChannelData; channel: ChannelData;
notification?: number;
isActive: boolean; isActive: boolean;
activeView?: boolean; activeView?: boolean;
onClick?: () => void; onClick?: () => void;
@ -61,6 +80,7 @@ export function Channel({
isActive, isActive,
activeView, activeView,
onClick, onClick,
notification,
}: ChannelProps) { }: ChannelProps) {
return ( return (
<ChannelWrapper <ChannelWrapper
@ -82,7 +102,11 @@ export function Channel({
<ChannelName <ChannelName
theme={theme} theme={theme}
className={ className={
isActive ? "active" : channel.notifications ? "notified" : "" isActive
? "active"
: notification && notification > 0
? "notified"
: ""
} }
> >
# {channel.name} # {channel.name}
@ -95,10 +119,8 @@ export function Channel({
)} )}
</ChannelTextInfo> </ChannelTextInfo>
</ChannelInfo> </ChannelInfo>
{channel.notifications && !activeView && ( {notification && notification > 0 && !activeView && (
<NotificationBagde theme={theme}> <NotificationBagde theme={theme}>{notification}</NotificationBagde>
{channel.notifications}
</NotificationBagde>
)} )}
</ChannelWrapper> </ChannelWrapper>
); );

View File

@ -2,6 +2,7 @@ import React, { useState } from "react";
import styled from "styled-components"; import styled from "styled-components";
import { ChannelData, channels } from "../helpers/channelsMock"; import { ChannelData, channels } from "../helpers/channelsMock";
import { useMessenger } from "../hooks/useMessenger";
import { Theme } from "../styles/themes"; import { Theme } from "../styles/themes";
import { Channels } from "./Channels"; import { Channels } from "./Channels";
@ -16,11 +17,23 @@ interface ChatProps {
export function Chat({ theme, channelsON, membersON }: ChatProps) { export function Chat({ theme, channelsON, membersON }: ChatProps) {
const [activeChannel, setActiveChannel] = useState<ChannelData>(channels[0]); const [activeChannel, setActiveChannel] = useState<ChannelData>(channels[0]);
const {
messenger,
messages,
sendMessage,
notifications,
clearNotifications,
} = useMessenger(
activeChannel.name,
channels.map((channel) => channel.name)
);
return ( return (
<ChatWrapper> <ChatWrapper>
{channelsON && ( {channelsON && (
<Channels <Channels
notifications={notifications}
clearNotifications={clearNotifications}
theme={theme} theme={theme}
icon={"https://www.cryptokitties.co/icons/logo.svg"} icon={"https://www.cryptokitties.co/icons/logo.svg"}
name={"CryptoKitties"} name={"CryptoKitties"}
@ -29,12 +42,31 @@ export function Chat({ theme, channelsON, membersON }: ChatProps) {
activeChannelId={activeChannel.id} activeChannelId={activeChannel.id}
/> />
)} )}
<ChatBody theme={theme} channel={activeChannel} /> {messenger ? (
<ChatBody
theme={theme}
channel={activeChannel}
messages={messages}
sendMessage={sendMessage}
/>
) : (
<Loading>Connecting to waku</Loading>
)}
{membersON && <Members theme={theme} />} {membersON && <Members theme={theme} />}
</ChatWrapper> </ChatWrapper>
); );
} }
const Loading = styled.div`
display: flex;
flex-direction: column;
flex: 1;
height: 100%;
text-align: center;
justify-content: center;
align-items: center;
`;
const ChatWrapper = styled.div` const ChatWrapper = styled.div`
width: 100%; width: 100%;
height: 100vh; height: 100vh;

View File

@ -2,7 +2,7 @@ import React from "react";
import styled from "styled-components"; import styled from "styled-components";
import { ChannelData } from "../../helpers/channelsMock"; import { ChannelData } from "../../helpers/channelsMock";
import { useMessenger } from "../../hooks/useMessenger"; import { ChatMessage } from "../../models/ChatMessage";
import { Theme } from "../../styles/themes"; import { Theme } from "../../styles/themes";
import { Channel } from "../Channels"; import { Channel } from "../Channels";
@ -12,11 +12,16 @@ import { ChatMessages } from "./ChatMessages";
interface ChatBodyProps { interface ChatBodyProps {
theme: Theme; theme: Theme;
channel: ChannelData; channel: ChannelData;
messages: ChatMessage[];
sendMessage: (text: string) => void;
} }
export function ChatBody({ theme, channel }: ChatBodyProps) { export function ChatBody({
const { messages, sendMessage } = useMessenger(channel.name); theme,
channel,
messages,
sendMessage,
}: ChatBodyProps) {
return ( return (
<ChatBodyWrapper theme={theme}> <ChatBodyWrapper theme={theme}>
<ChannelWrapper> <ChannelWrapper>

View File

@ -1,17 +1,29 @@
import { StoreCodec } from "js-waku"; // import { StoreCodec } from "js-waku";
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { Identity, Messenger } from "status-communities/dist/cjs"; import { Identity, Messenger } from "status-communities/dist/cjs";
import { ChatMessage } from "../models/ChatMessage"; import { ChatMessage } from "../models/ChatMessage";
export function useMessenger(chatId: string) { export function useMessenger(chatId: string, chatIdList: string[]) {
const [messenger, setMessenger] = useState<Messenger | undefined>(undefined); const [messenger, setMessenger] = useState<Messenger | undefined>(undefined);
const [messages, setMessages] = useState<{ [chatId: string]: ChatMessage[] }>( const [messages, setMessages] = useState<{ [chatId: string]: ChatMessage[] }>(
{} {}
); );
const [notifications, setNotifications] = useState<{
[chatId: string]: number;
}>({});
const clearNotifications = useCallback((id: string) => {
setNotifications((prevNotifications) => {
return {
...prevNotifications,
[id]: 0,
};
});
}, []);
const addNewMessage = useCallback( const addNewMessage = useCallback(
(sender: Uint8Array, content: string, date: Date) => { (sender: Uint8Array, content: string, date: Date, id: string) => {
let signer = "0x"; let signer = "0x";
sender.forEach((e) => { sender.forEach((e) => {
signer = signer + e.toString(16); signer = signer + e.toString(16);
@ -22,87 +34,76 @@ export function useMessenger(chatId: string) {
content: content, content: content,
date: date, date: date,
}; };
return { if (prevMessages?.[id]) {
...prevMessages, return {
[chatId]: [...prevMessages[chatId], newMessage], ...prevMessages,
}; [id]: [...prevMessages[id], newMessage],
};
} else {
return {
...prevMessages,
[id]: [newMessage],
};
}
}); });
if (chatId != id) {
setNotifications((prevNotifications) => {
return {
...prevNotifications,
[id]: prevNotifications[id] + 1,
};
});
}
}, },
[chatId] []
); );
useEffect(() => { useEffect(() => {
const createMessenger = async () => { const createMessenger = async () => {
const identity = Identity.generate(); const identity = Identity.generate();
const messenger = await Messenger.create(identity); const messenger = await Messenger.create(identity);
await new Promise((resolve) => { await new Promise((resolve) =>
messenger.waku?.libp2p.peerStore.on( messenger.waku.libp2p.pubsub.once("pubsub:subscription-change", () =>
"change:protocols", resolve(null)
({ protocols }) => { )
if (protocols.includes(StoreCodec)) { );
resolve(""); await Promise.all(
} chatIdList.map(async (id) => {
} await messenger.joinChat(id);
); clearNotifications(id);
}); messenger.addObserver((message) => {
await messenger.joinChat(chatId); addNewMessage(
setMessages((prevMessages) => { message.signer ?? new Uint8Array(),
return { ...prevMessages, [chatId]: [] }; message.chatMessage?.text ?? "",
}); new Date(message.chatMessage?.proto.timestamp ?? 0),
const chat = messenger.chatsById.get(chatId); id
const contentTopic = chat?.contentTopic; );
}, id);
if (contentTopic) { })
const messages = await messenger.waku.store.queryHistory( );
[contentTopic],
{ decryptionKeys: [chat?.symKey] }
);
console.log(messages);
}
messenger.addObserver((message) => {
addNewMessage(
message.signer ?? new Uint8Array(),
message.chatMessage?.text ?? "",
new Date(message.chatMessage?.proto.timestamp ?? 0)
);
}, chatId);
setMessenger(messenger); setMessenger(messenger);
}; };
createMessenger(); createMessenger();
}, []); }, []);
useEffect(() => {
const joinNewChat = async () => {
try {
await messenger?.joinChat(chatId);
setMessages((prevMessages) => {
return { ...prevMessages, [chatId]: [] };
});
messenger?.addObserver((message) => {
addNewMessage(
message.signer ?? new Uint8Array(),
message.chatMessage?.text ?? "",
new Date(message.chatMessage?.proto.timestamp ?? 0)
);
}, chatId);
} catch {
return;
}
};
joinNewChat();
}, [chatId]);
const sendMessage = useCallback( const sendMessage = useCallback(
async (messageText: string) => { async (messageText: string) => {
await messenger?.sendMessage(messageText, chatId); await messenger?.sendMessage(messageText, chatId);
addNewMessage( addNewMessage(
messenger?.identity.publicKey ?? new Uint8Array(), messenger?.identity.publicKey ?? new Uint8Array(),
messageText, messageText,
new Date() new Date(),
chatId
); );
}, },
[chatId, messenger] [chatId, messenger]
); );
return { messenger, messages: messages?.[chatId] ?? [], sendMessage }; return {
messenger,
messages: messages?.[chatId] ?? [],
sendMessage,
notifications,
clearNotifications,
};
} }