Use community api (#84)

This commit is contained in:
Szymon Szlachtowicz 2021-10-19 13:12:44 +02:00 committed by GitHub
parent e8a754f418
commit bb710034c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 111 additions and 42 deletions

View File

@ -1,4 +1,4 @@
import { community, lightTheme, ReactChat } from "@dappconnect/react-chat"; import { lightTheme, ReactChat } from "@dappconnect/react-chat";
import React, { useRef, useState } from "react"; import React, { useRef, useState } from "react";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import styled from "styled-components"; import styled from "styled-components";
@ -65,7 +65,9 @@ function DragDiv() {
<FloatingDiv className={showChat ? "" : "hide"}> <FloatingDiv className={showChat ? "" : "hide"}>
<ReactChat <ReactChat
theme={lightTheme} theme={lightTheme}
community={community} communityKey={
"0x0262c65c881f5a9f79343a26faaa02aad3af7c533d9445fb1939ed11b8bf4d2abd"
}
fetchMetadata={fetchMetadata} fetchMetadata={fetchMetadata}
/> />
</FloatingDiv> </FloatingDiv>

View File

@ -1,7 +1,7 @@
import React, { useEffect } 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 } from "../../helpers/channelsMock";
import { Channel } from "./Channel"; import { Channel } from "./Channel";
@ -9,7 +9,8 @@ interface ChannelsProps {
notifications: { [id: string]: number }; notifications: { [id: string]: number };
clearNotifications: (id: string) => void; clearNotifications: (id: string) => void;
onCommunityClick: (val: ChannelData) => void; onCommunityClick: (val: ChannelData) => void;
activeChannelId: number; activeChannelId: string;
channels: ChannelData[];
} }
export function Channels({ export function Channels({
@ -17,6 +18,7 @@ export function Channels({
onCommunityClick, onCommunityClick,
clearNotifications, clearNotifications,
activeChannelId, activeChannelId,
channels,
}: ChannelsProps) { }: ChannelsProps) {
useEffect(() => { useEffect(() => {
const channel = channels.find((channel) => channel.id === activeChannelId); const channel = channels.find((channel) => channel.id === activeChannelId);

View File

@ -1,9 +1,9 @@
import React, { useState } from "react"; import React, { useEffect, useMemo, useState } from "react";
import styled from "styled-components"; import styled from "styled-components";
import { useNarrow } from "../contexts/narrowProvider"; import { useNarrow } from "../contexts/narrowProvider";
import { ChannelData, channels } from "../helpers/channelsMock"; import { ChannelData } from "../helpers/channelsMock";
import { CommunityData } from "../helpers/communityMock"; import { uintToImgUrl } from "../helpers/uintToImgUrl";
import { useMessenger } from "../hooks/useMessenger"; import { useMessenger } from "../hooks/useMessenger";
import { Metadata } from "../models/Metadata"; import { Metadata } from "../models/Metadata";
import { Theme } from "../styles/themes"; import { Theme } from "../styles/themes";
@ -16,12 +16,16 @@ import { CommunityModal } from "./Modals/CommunityModal";
interface ChatProps { interface ChatProps {
theme: Theme; theme: Theme;
community: CommunityData; communityKey: string;
fetchMetadata?: (url: string) => Promise<Metadata | undefined>; fetchMetadata?: (url: string) => Promise<Metadata | undefined>;
} }
export function Chat({ theme, community, fetchMetadata }: ChatProps) { export function Chat({ theme, communityKey, fetchMetadata }: ChatProps) {
const [activeChannel, setActiveChannel] = useState<ChannelData>(channels[0]); const [activeChannel, setActiveChannel] = useState<ChannelData>({
id: "",
name: "",
description: "",
});
const [showMembers, setShowMembers] = useState(true); const [showMembers, setShowMembers] = useState(true);
const [showChannels, setShowChannels] = useState(true); const [showChannels, setShowChannels] = useState(true);
const narrow = useNarrow(); const narrow = useNarrow();
@ -34,24 +38,67 @@ export function Chat({ theme, community, fetchMetadata }: ChatProps) {
clearNotifications, clearNotifications,
loadNextDay, loadNextDay,
loadingMessages, loadingMessages,
} = useMessenger( community,
activeChannel.name, } = useMessenger(activeChannel?.id ?? "", communityKey);
channels.map((channel) => channel.name)
);
const [isModalVisible, setIsModalVisible] = useState(false); const [isModalVisible, setIsModalVisible] = useState(false);
const showModal = () => setIsModalVisible(true); const showModal = () => setIsModalVisible(true);
const communityData = useMemo(() => {
if (community?.description) {
return {
id: 1,
name: community.description.identity?.displayName ?? "",
icon: uintToImgUrl(
community.description?.identity?.images?.thumbnail.payload ??
new Uint8Array()
),
members: 0,
membersList: [],
description: community.description.identity?.description ?? "",
};
} else {
return {
id: 1,
name: "",
icon: "",
members: 0,
membersList: [],
description: "",
};
}
}, [community]);
const channels = useMemo(() => {
console.log(community?.chats);
if (community?.chats) {
return Array.from(community.chats.values()).map((chat) => {
return {
id: chat.id,
name: chat.communityChat?.identity?.displayName ?? "",
description: chat.communityChat?.identity?.description ?? "",
};
});
} else {
return [];
}
}, [community]);
useEffect(() => {
if (channels.length > 0) setActiveChannel(channels[0]);
}, [channels]);
return ( return (
<ChatWrapper> <ChatWrapper>
{showChannels && !narrow && ( {showChannels && !narrow && (
<ChannelsWrapper> <ChannelsWrapper>
<StyledCommunity onClick={showModal} community={community} /> <StyledCommunity onClick={showModal} community={communityData} />
<Channels <Channels
notifications={notifications} notifications={notifications}
clearNotifications={clearNotifications} clearNotifications={clearNotifications}
onCommunityClick={(e) => setActiveChannel(e)} onCommunityClick={(e) => setActiveChannel(e)}
activeChannelId={activeChannel.id} activeChannelId={activeChannel?.id ?? ""}
channels={channels}
/> />
</ChannelsWrapper> </ChannelsWrapper>
)} )}
@ -66,25 +113,26 @@ export function Chat({ theme, community, fetchMetadata }: ChatProps) {
activeChannelId={activeChannel.id} activeChannelId={activeChannel.id}
onClick={() => setShowMembers(!showMembers)} onClick={() => setShowMembers(!showMembers)}
showMembers={showMembers} showMembers={showMembers}
community={community} community={communityData}
showCommunity={!showChannels} showCommunity={!showChannels}
loadNextDay={() => loadNextDay(activeChannel.name)} loadNextDay={() => loadNextDay(activeChannel.name)}
onCommunityClick={showModal} onCommunityClick={showModal}
fetchMetadata={fetchMetadata} fetchMetadata={fetchMetadata}
loadingMessages={loadingMessages} loadingMessages={loadingMessages}
clearNotifications={clearNotifications} clearNotifications={clearNotifications}
channels={channels}
/> />
{showMembers && !narrow && ( {showMembers && !narrow && (
<Members community={community} setShowChannels={setShowChannels} /> <Members community={communityData} setShowChannels={setShowChannels} />
)} )}
<CommunityModal <CommunityModal
isVisible={isModalVisible} isVisible={isModalVisible}
onClose={() => setIsModalVisible(false)} onClose={() => setIsModalVisible(false)}
icon={community.icon} icon={communityData.icon}
name={community.name} name={communityData.name}
subtitle="Public Community" subtitle="Public Community"
description={community.description} description={communityData.description}
publicKey="0xD95DBdaB08A9FED2D71ac9C3028AAc40905d8CF3" publicKey={communityKey}
/> />
</ChatWrapper> </ChatWrapper>
); );

View File

@ -31,12 +31,13 @@ interface ChatBodyProps {
showCommunity: boolean; showCommunity: boolean;
notifications: { [id: string]: number }; notifications: { [id: string]: number };
setActiveChannel: (val: ChannelData) => void; setActiveChannel: (val: ChannelData) => void;
activeChannelId: number; activeChannelId: string;
loadNextDay: () => void; loadNextDay: () => void;
onCommunityClick: () => void; onCommunityClick: () => void;
fetchMetadata?: (url: string) => Promise<Metadata | undefined>; fetchMetadata?: (url: string) => Promise<Metadata | undefined>;
loadingMessages: boolean; loadingMessages: boolean;
clearNotifications: (id: string) => void; clearNotifications: (id: string) => void;
channels: ChannelData[];
} }
export function ChatBody({ export function ChatBody({
@ -57,6 +58,7 @@ export function ChatBody({
fetchMetadata, fetchMetadata,
loadingMessages, loadingMessages,
clearNotifications, clearNotifications,
channels,
}: ChatBodyProps) { }: ChatBodyProps) {
const narrow = useNarrow(); const narrow = useNarrow();
const [showChannelsList, setShowChannelsList] = useState(false); const [showChannelsList, setShowChannelsList] = useState(false);
@ -137,6 +139,7 @@ export function ChatBody({
{showChannelsList && narrow && ( {showChannelsList && narrow && (
<NarrowChannels <NarrowChannels
channels={channels}
community={community.name} community={community.name}
notifications={notifications} notifications={notifications}
setActiveChannel={setActiveChannel} setActiveChannel={setActiveChannel}

View File

@ -10,9 +10,10 @@ interface NarrowChannelsProps {
community: string; community: string;
notifications: { [id: string]: number }; notifications: { [id: string]: number };
setActiveChannel: (val: ChannelData) => void; setActiveChannel: (val: ChannelData) => void;
activeChannelId: number; activeChannelId: string;
setShowChannels: (val: boolean) => void; setShowChannels: (val: boolean) => void;
clearNotifications: (id: string) => void; clearNotifications: (id: string) => void;
channels: ChannelData[];
} }
export function NarrowChannels({ export function NarrowChannels({
@ -22,6 +23,7 @@ export function NarrowChannels({
activeChannelId, activeChannelId,
setShowChannels, setShowChannels,
clearNotifications, clearNotifications,
channels,
}: NarrowChannelsProps) { }: NarrowChannelsProps) {
return ( return (
<ListWrapper> <ListWrapper>
@ -34,6 +36,7 @@ export function NarrowChannels({
setShowChannels(false); setShowChannels(false);
}} }}
activeChannelId={activeChannelId} activeChannelId={activeChannelId}
channels={channels}
/> />
</ListWrapper> </ListWrapper>
); );

View File

@ -3,7 +3,6 @@ import { ThemeProvider } from "styled-components";
import styled from "styled-components"; import styled from "styled-components";
import { NarrowProvider } from "../contexts/narrowProvider"; import { NarrowProvider } from "../contexts/narrowProvider";
import { CommunityData } from "../helpers/communityMock";
import { Metadata } from "../models/Metadata"; import { Metadata } from "../models/Metadata";
import { GlobalStyle } from "../styles/GlobalStyle"; import { GlobalStyle } from "../styles/GlobalStyle";
import { Theme } from "../styles/themes"; import { Theme } from "../styles/themes";
@ -12,11 +11,15 @@ import { Chat } from "./Chat";
interface ReactChatProps { interface ReactChatProps {
theme: Theme; theme: Theme;
community: CommunityData; communityKey: string;
fetchMetadata?: (url: string) => Promise<Metadata | undefined>; fetchMetadata?: (url: string) => Promise<Metadata | undefined>;
} }
export function ReactChat({ theme, community, fetchMetadata }: ReactChatProps) { export function ReactChat({
theme,
communityKey,
fetchMetadata,
}: ReactChatProps) {
const ref = useRef<HTMLHeadingElement>(null); const ref = useRef<HTMLHeadingElement>(null);
return ( return (
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
@ -24,7 +27,7 @@ export function ReactChat({ theme, community, fetchMetadata }: ReactChatProps) {
<Wrapper ref={ref}> <Wrapper ref={ref}>
<GlobalStyle /> <GlobalStyle />
<Chat <Chat
community={community} communityKey={communityKey}
fetchMetadata={fetchMetadata} fetchMetadata={fetchMetadata}
theme={theme} theme={theme}
/> />

View File

@ -1,9 +1,8 @@
export type ChannelData = { export type ChannelData = {
id: number; id: string;
name: string; name: string;
description: string; description: string;
icon?: string; icon?: string;
notifications?: number;
isMuted?: boolean; isMuted?: boolean;
}; };

View File

@ -1,7 +1,7 @@
// import { StoreCodec } from "js-waku"; // import { StoreCodec } from "js-waku";
import { StoreCodec } from "js-waku"; import { StoreCodec } from "js-waku";
import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { Identity, Messenger } from "status-communities/dist/cjs"; import { Community, Identity, Messenger } from "status-communities/dist/cjs";
import { ApplicationMetadataMessage } from "status-communities/dist/cjs"; import { ApplicationMetadataMessage } from "status-communities/dist/cjs";
import { uintToImgUrl } from "../helpers/uintToImgUrl"; import { uintToImgUrl } from "../helpers/uintToImgUrl";
@ -32,11 +32,12 @@ function binarySetInsert<T>(
return arr; return arr;
} }
export function useMessenger(chatId: string, chatIdList: string[]) { export function useMessenger(chatId: string, communityKey: 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 [community, setCommunity] = useState<Community | undefined>(undefined);
const [notifications, setNotifications] = useState<{ const [notifications, setNotifications] = useState<{
[chatId: string]: number; [chatId: string]: number;
}>({}); }>({});
@ -105,7 +106,7 @@ export function useMessenger(chatId: string, chatIdList: string[]) {
const loadNextDay = useCallback( const loadNextDay = useCallback(
async (id: string) => { async (id: string) => {
if (messenger) { if (messenger) {
const endTime = lastLoadTime.current[id]; const endTime = lastLoadTime.current[id] ?? new Date();
const startTime = new Date(endTime.getTime() - _MS_PER_DAY); const startTime = new Date(endTime.getTime() - _MS_PER_DAY);
const timeDiff = Math.floor( const timeDiff = Math.floor(
(new Date().getTime() - endTime.getTime()) / _MS_PER_DAY (new Date().getTime() - endTime.getTime()) / _MS_PER_DAY
@ -139,6 +140,7 @@ export function useMessenger(chatId: string, chatIdList: string[]) {
const createMessenger = async () => { const createMessenger = async () => {
// Test password for now // Test password for now
// Need design for password input // Need design for password input
let identity = await loadIdentity("test"); let identity = await loadIdentity("test");
if (!identity) { if (!identity) {
identity = Identity.generate(); identity = Identity.generate();
@ -164,16 +166,20 @@ export function useMessenger(chatId: string, chatIdList: string[]) {
} }
); );
}); });
const community = await Community.instantiateCommunity(
communityKey,
messenger.waku
);
setCommunity(community);
await Promise.all( await Promise.all(
chatIdList.map(async (id) => { Array.from(community.chats.values()).map(async (chat) => {
await messenger.joinChatById(id); await messenger.joinChat(chat);
lastLoadTime.current[id] = new Date(); lastLoadTime.current[chat.id] = new Date();
messenger.addObserver( messenger.addObserver(
(msg, date) => addNewMessage(msg, id, date), (msg, date) => addNewMessage(msg, chat.id, date),
id chat.id
); );
clearNotifications(id); clearNotifications(chat.id);
}) })
); );
setMessenger(messenger); setMessenger(messenger);
@ -182,8 +188,10 @@ export function useMessenger(chatId: string, chatIdList: string[]) {
}, []); }, []);
useEffect(() => { useEffect(() => {
if (messenger) { if (messenger && community?.chats) {
chatIdList.forEach(loadNextDay); Array.from(community?.chats.values()).forEach(({ id }) =>
loadNextDay(id)
);
} }
}, [messenger]); }, [messenger]);
@ -224,5 +232,6 @@ export function useMessenger(chatId: string, chatIdList: string[]) {
loadNextDay, loadNextDay,
lastMessage, lastMessage,
loadingMessages, loadingMessages,
community,
}; };
} }