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

View File

@ -2,6 +2,7 @@ import React, { useState } from "react";
import styled from "styled-components";
import { ChannelData, channels } from "../helpers/channelsMock";
import { useMessenger } from "../hooks/useMessenger";
import { Theme } from "../styles/themes";
import { Channels } from "./Channels";
@ -16,11 +17,23 @@ interface ChatProps {
export function Chat({ theme, channelsON, membersON }: ChatProps) {
const [activeChannel, setActiveChannel] = useState<ChannelData>(channels[0]);
const {
messenger,
messages,
sendMessage,
notifications,
clearNotifications,
} = useMessenger(
activeChannel.name,
channels.map((channel) => channel.name)
);
return (
<ChatWrapper>
{channelsON && (
<Channels
notifications={notifications}
clearNotifications={clearNotifications}
theme={theme}
icon={"https://www.cryptokitties.co/icons/logo.svg"}
name={"CryptoKitties"}
@ -29,12 +42,31 @@ export function Chat({ theme, channelsON, membersON }: ChatProps) {
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} />}
</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`
width: 100%;
height: 100vh;

View File

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

View File

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