Improve use messenger (#18)
This commit is contained in:
parent
c9246acd1e
commit
c07d912c39
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue