Fix hook problems (#216)

This commit is contained in:
Szymon Szlachtowicz 2022-02-03 08:57:05 +01:00 committed by GitHub
parent 030a33f95a
commit bf7c15bc29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 354 additions and 252 deletions

View File

@ -30,7 +30,7 @@ export function ActivityCenter({
activities.filter( activities.filter(
(activity) => !contacts?.[activity.user]?.blocked ?? true (activity) => !contacts?.[activity.user]?.blocked ?? true
), ),
[contacts, activities, activities.length] [contacts, activities]
); );
const [hideRead, setHideRead] = useState(false); const [hideRead, setHideRead] = useState(false);

View File

@ -3,9 +3,9 @@ import styled from "styled-components";
import { useMessengerContext } from "../../contexts/messengerProvider"; import { useMessengerContext } from "../../contexts/messengerProvider";
import { useModal } from "../../contexts/modalProvider"; import { useModal } from "../../contexts/modalProvider";
import { useScrollToMessage } from "../../contexts/scrollProvider";
import { ActivityAction } from "../../hooks/useActivities"; import { ActivityAction } from "../../hooks/useActivities";
import { useClickOutside } from "../../hooks/useClickOutside"; import { useClickOutside } from "../../hooks/useClickOutside";
import { useScrollToMessage } from "../../hooks/useScrollToMessage";
import { Activity } from "../../models/Activity"; import { Activity } from "../../models/Activity";
import { equalDate } from "../../utils/equalDate"; import { equalDate } from "../../utils/equalDate";
import { DownloadButton } from "../Buttons/DownloadButton"; import { DownloadButton } from "../Buttons/DownloadButton";
@ -169,7 +169,10 @@ export function ActivityMessage({
<ActivityText> <ActivityText>
{"message" in activity && activity.message?.content && ( {"message" in activity && activity.message?.content && (
<div <div
onClick={() => scroll(activity.message, activity.channel.id)} onClick={() => {
scroll(activity.message, activity.channel.id);
setShowActivityCenter(false);
}}
> >
{elements.map((el) => el)} {elements.map((el) => el)}
</div> </div>

View File

@ -1,8 +1,7 @@
import { utils } from "@waku/status-communities/dist/cjs";
import React, { useMemo } from "react"; import React, { useMemo } from "react";
import styled from "styled-components"; import styled from "styled-components";
import { useIdentity } from "../../contexts/identityProvider"; import { useUserPublicKey } from "../../contexts/identityProvider";
import { useMessengerContext } from "../../contexts/messengerProvider"; import { useMessengerContext } from "../../contexts/messengerProvider";
import { useNarrow } from "../../contexts/narrowProvider"; import { useNarrow } from "../../contexts/narrowProvider";
import { ChannelData } from "../../models/ChannelData"; import { ChannelData } from "../../models/ChannelData";
@ -16,17 +15,16 @@ type ChannelBeggingTextProps = {
}; };
function ChannelBeggingText({ channel }: ChannelBeggingTextProps) { function ChannelBeggingText({ channel }: ChannelBeggingTextProps) {
const identity = useIdentity(); const userPK = useUserPublicKey();
const { contacts } = useMessengerContext(); const { contacts } = useMessengerContext();
const members = useMemo(() => { const members = useMemo(() => {
if (channel?.members && identity) { if (channel?.members && userPK) {
const publicKey = utils.bufToHex(identity.publicKey);
return channel.members return channel.members
.filter((contact) => contact.id !== publicKey) .filter((contact) => contact.id !== userPK)
.map((member) => contacts?.[member.id] ?? member); .map((member) => contacts?.[member.id] ?? member);
} }
return []; return [];
}, [channel, contacts]); }, [channel, contacts, userPK]);
switch (channel.type) { switch (channel.type) {
case "dm": case "dm":
@ -40,8 +38,7 @@ function ChannelBeggingText({ channel }: ChannelBeggingTextProps) {
case "group": case "group":
return ( return (
<EmptyTextGroup> <EmptyTextGroup>
{identity && <span>{utils.bufToHex(identity.publicKey)}</span>}{" "} {userPK && <span>{userPK}</span>} created a group with{" "}
created a group with{" "}
{members.map((contact, idx) => ( {members.map((contact, idx) => (
<span key={contact.id}> <span key={contact.id}>
{contact?.customName ?? contact.trueName.slice(0, 10)} {contact?.customName ?? contact.trueName.slice(0, 10)}

View File

@ -116,19 +116,21 @@ export function ChatBody({
activeChannel={activeChannel} activeChannel={activeChannel}
/> />
) : ( ) : (
<ChatTopbar <>
onClick={onClick} <ChatTopbar
setEditGroup={setEditGroup} onClick={onClick}
showMembers={showMembers} setEditGroup={setEditGroup}
showState={showState} showMembers={showMembers}
switchShowState={switchShowState} showState={showState}
/> switchShowState={switchShowState}
/>
<ChatBodyContent
showState={showState}
switchShowState={switchShowState}
channel={activeChannel}
/>
</>
)} )}
<ChatBodyContent
showState={showState}
switchShowState={switchShowState}
channel={activeChannel}
/>
</ChatBodyWrapper> </ChatBodyWrapper>
{!permission && ( {!permission && (
<BluredWrapper> <BluredWrapper>

View File

@ -1,9 +1,8 @@
import { bufToHex } from "@waku/status-communities/dist/cjs/utils"; import React, { useCallback, useMemo, useState } from "react";
import React, { useCallback, useState } from "react";
import styled from "styled-components"; import styled from "styled-components";
import { ChatState, useChatState } from "../../contexts/chatStateProvider"; import { ChatState, useChatState } from "../../contexts/chatStateProvider";
import { useIdentity } from "../../contexts/identityProvider"; import { useUserPublicKey } from "../../contexts/identityProvider";
import { useMessengerContext } from "../../contexts/messengerProvider"; import { useMessengerContext } from "../../contexts/messengerProvider";
import { useNarrow } from "../../contexts/narrowProvider"; import { useNarrow } from "../../contexts/narrowProvider";
import { ChannelData } from "../../models/ChannelData"; import { ChannelData } from "../../models/ChannelData";
@ -27,19 +26,23 @@ export function ChatCreation({
activeChannel, activeChannel,
}: ChatCreationProps) { }: ChatCreationProps) {
const narrow = useNarrow(); const narrow = useNarrow();
const identity = useIdentity(); const userPK = useUserPublicKey();
const [query, setQuery] = useState(""); const [query, setQuery] = useState("");
const [styledGroup, setStyledGroup] = useState<string[]>( const [groupChatMembersIds, setGroupChatMembersIds] = useState<string[]>(
activeChannel?.members?.map( activeChannel?.members?.map((member) => member.id) ?? []
(member) => member?.customName ?? member.trueName
) ?? []
); );
const { contacts, createGroupChat, addMembers } = useMessengerContext(); const { contacts, createGroupChat, addMembers } = useMessengerContext();
const groupChatMembers = useMemo(
() => groupChatMembersIds.map((id) => contacts[id]).filter((e) => !!e),
[groupChatMembersIds, contacts]
);
const setChatState = useChatState()[1]; const setChatState = useChatState()[1];
const addMember = useCallback( const addMember = useCallback(
(member: string) => { (member: string) => {
setStyledGroup((prevMembers: string[]) => { setGroupChatMembersIds((prevMembers: string[]) => {
if ( if (
prevMembers.find((mem) => mem === member) || prevMembers.find((mem) => mem === member) ||
prevMembers.length >= 5 prevMembers.length >= 5
@ -50,33 +53,44 @@ export function ChatCreation({
} }
}); });
setQuery(""); setQuery("");
if (activeChannel) addMembers(styledGroup, activeChannel.id);
}, },
[setStyledGroup, styledGroup] [setGroupChatMembersIds]
); );
const removeMember = useCallback( const removeMember = useCallback(
(member: string) => { (member: string) => {
setStyledGroup((prev) => prev.filter((e) => e != member)); setGroupChatMembersIds((prev) => prev.filter((e) => e != member));
}, },
[setStyledGroup] [setGroupChatMembersIds]
); );
const createChat = useCallback( const createChat = useCallback(
(group: string[]) => { (group: string[]) => {
if (identity) { if (userPK) {
const newGroup = group.slice(); const newGroup = group.slice();
newGroup.push(bufToHex(identity.publicKey)); newGroup.push(userPK);
createGroupChat(newGroup); createGroupChat(newGroup);
setChatState(ChatState.ChatBody); setChatState(ChatState.ChatBody);
} }
}, },
[identity, createGroupChat] [userPK, createGroupChat, setChatState]
); );
const handleCreationClick = useCallback(() => {
if (!activeChannel) {
createChat(groupChatMembers.map((member) => member.id));
} else {
addMembers(
groupChatMembers.map((member) => member.id),
activeChannel.id
);
}
setEditGroup?.(false);
}, [activeChannel, groupChatMembers, createChat, addMembers, setEditGroup]);
return ( return (
<CreationWrapper className={`${narrow && "narrow"}`}> <CreationWrapper className={`${narrow && "narrow"}`}>
<CreationBar <CreationBar
className={`${styledGroup.length === 5 && narrow && "limit"}`} className={`${groupChatMembers.length === 5 && narrow && "limit"}`}
> >
{narrow && ( {narrow && (
<BackButton <BackButton
@ -88,16 +102,19 @@ export function ChatCreation({
<InputBar> <InputBar>
<InputText>To:</InputText> <InputText>To:</InputText>
<StyledList> <StyledList>
{styledGroup.map((member) => ( {groupChatMembers.map((member) => (
<StyledMember key={member}> <StyledMember key={member.id}>
<StyledName>{member.slice(0, 10)}</StyledName> <StyledName>
<CloseButton onClick={() => removeMember(member)}> {member?.customName?.slice(0, 10) ??
member.trueName.slice(0, 10)}
</StyledName>
<CloseButton onClick={() => removeMember(member.id)}>
<CrossIcon memberView={true} /> <CrossIcon memberView={true} />
</CloseButton> </CloseButton>
</StyledMember> </StyledMember>
))} ))}
</StyledList> </StyledList>
{styledGroup.length < 5 && ( {groupChatMembers.length < 5 && (
<SearchMembers> <SearchMembers>
<Input <Input
value={query} value={query}
@ -105,31 +122,24 @@ export function ChatCreation({
/> />
</SearchMembers> </SearchMembers>
)} )}
{!narrow && styledGroup.length === 5 && ( {!narrow && groupChatMembers.length === 5 && (
<LimitAlert>5 user Limit reached</LimitAlert> <LimitAlert>5 user Limit reached</LimitAlert>
)} )}
</InputBar> </InputBar>
{narrow && styledGroup.length === 5 && ( {narrow && groupChatMembers.length === 5 && (
<LimitAlert className="narrow">5 user Limit reached</LimitAlert> <LimitAlert className="narrow">5 user Limit reached</LimitAlert>
)} )}
</Column> </Column>
<CreationBtn <CreationBtn
disabled={styledGroup.length === 0} disabled={groupChatMembers.length === 0}
onClick={() => { onClick={handleCreationClick}
if (!activeChannel) {
createChat(styledGroup);
} else {
addMembers(styledGroup, activeChannel.id);
}
setEditGroup?.(false);
}}
> >
Confirm Confirm
</CreationBtn> </CreationBtn>
{!narrow && <ActivityButton className="creation" />} {!narrow && <ActivityButton className="creation" />}
<SearchBlock <SearchBlock
query={query} query={query}
discludeList={styledGroup} discludeList={groupChatMembersIds}
onClick={addMember} onClick={addMember}
/> />
</CreationBar> </CreationBar>
@ -137,13 +147,11 @@ export function ChatCreation({
<Contacts> <Contacts>
<ContactsHeading>Contacts</ContactsHeading> <ContactsHeading>Contacts</ContactsHeading>
<ContactsList> <ContactsList>
{identity && {userPK &&
!query && !query &&
Object.values(contacts) Object.values(contacts)
.filter( .filter(
(e) => (e) => e.id != userPK && !groupChatMembersIds.includes(e.id)
e.id != bufToHex(identity.publicKey) &&
!styledGroup.includes(e.id)
) )
.map((contact) => ( .map((contact) => (
<Member <Member
@ -157,7 +165,10 @@ export function ChatCreation({
</Contacts> </Contacts>
)} )}
{!activeChannel && ( {!activeChannel && (
<ChatInput createChat={createChat} group={styledGroup} /> <ChatInput
createChat={createChat}
group={groupChatMembers.map((member) => member.id)}
/>
)} )}
</CreationWrapper> </CreationWrapper>
); );

View File

@ -1,3 +1,4 @@
import { EmojiData } from "emoji-mart";
import React, { import React, {
useCallback, useCallback,
useEffect, useEffect,
@ -72,16 +73,23 @@ export function ChatInput({
[imageUint] [imageUint]
); );
const addEmoji = useCallback((e: any) => { const addEmoji = useCallback(
const sym = e.unified.split("-"); (e: EmojiData) => {
const codesArray: any[] = []; if ("unified" in e) {
sym.forEach((el: string) => codesArray.push("0x" + el)); const sym = e.unified.split("-");
const emoji = String.fromCodePoint(...codesArray); const codesArray: string[] = [];
if (inputRef.current) { sym.forEach((el: string) => codesArray.push("0x" + el));
inputRef.current.appendChild(document.createTextNode(emoji)); const emoji = String.fromCodePoint(
} ...(codesArray as unknown as number[])
setContent((p) => p + emoji); );
}, []); if (inputRef.current) {
inputRef.current.appendChild(document.createTextNode(emoji));
}
setContent((p) => p + emoji);
}
},
[setContent]
);
const resizeTextArea = useCallback((target: HTMLDivElement) => { const resizeTextArea = useCallback((target: HTMLDivElement) => {
target.style.height = "40px"; target.style.height = "40px";
@ -91,31 +99,37 @@ export function ChatInput({
const rowHeight = inputHeight + (image ? 73 : 0); const rowHeight = inputHeight + (image ? 73 : 0);
const onInputChange = useCallback((e: React.ChangeEvent<HTMLDivElement>) => { const onInputChange = useCallback(
const element = document.getSelection(); (e: React.ChangeEvent<HTMLDivElement>) => {
const inputElement = inputRef.current; const element = document.getSelection();
if (inputElement && element && element.rangeCount > 0) { const inputElement = inputRef.current;
const selection = element?.getRangeAt(0)?.startOffset; if (inputElement && element && element.rangeCount > 0) {
const parentElement = element.anchorNode?.parentElement; const selection = element?.getRangeAt(0)?.startOffset;
if (parentElement && parentElement.tagName === "B") { const parentElement = element.anchorNode?.parentElement;
parentElement.outerHTML = parentElement.innerText; if (parentElement && parentElement.tagName === "B") {
const range = document.createRange(); parentElement.outerHTML = parentElement.innerText;
const sel = window.getSelection(); const range = document.createRange();
if (element.anchorNode.firstChild) { const sel = window.getSelection();
const childNumber = if (element.anchorNode.firstChild) {
element.focusOffset === 0 ? 0 : element.focusOffset - 1; const childNumber =
range.setStart(element.anchorNode.childNodes[childNumber], selection); element.focusOffset === 0 ? 0 : element.focusOffset - 1;
} range.setStart(
range.collapse(true); element.anchorNode.childNodes[childNumber],
selection
);
}
range.collapse(true);
sel?.removeAllRanges(); sel?.removeAllRanges();
sel?.addRange(range); sel?.addRange(range);
}
} }
} const target = e.target;
const target = e.target; resizeTextArea(target);
resizeTextArea(target); setContent(target.textContent ?? "");
setContent(target.textContent ?? ""); },
}, []); [resizeTextArea]
);
const onInputKeyPress = useCallback( const onInputKeyPress = useCallback(
(e: React.KeyboardEvent<HTMLDivElement>) => { (e: React.KeyboardEvent<HTMLDivElement>) => {
@ -137,7 +151,16 @@ export function ChatInput({
} }
} }
}, },
[content, imageUint] [
content,
imageUint,
createChat,
group,
sendMessage,
reply?.id,
setChatState,
setReply,
]
); );
const [selectedElement, setSelectedElement] = useState<{ const [selectedElement, setSelectedElement] = useState<{
@ -176,7 +199,7 @@ export function ChatInput({
} }
}, []); }, []);
useEffect(handleCursorChange, [content]); useEffect(handleCursorChange, [content, handleCursorChange]);
const addMention = useCallback( const addMention = useCallback(
(contact: string) => { (contact: string) => {
@ -215,7 +238,7 @@ export function ChatInput({
} }
} }
}, },
[inputRef, inputRef?.current, content, selectedElement] [inputRef, content, selectedElement, resizeTextArea]
); );
return ( return (

View File

@ -1,10 +1,9 @@
import { utils } from "@waku/status-communities/dist/cjs";
import { decode } from "html-entities"; import { decode } from "html-entities";
import React, { useEffect, useMemo, useRef, useState } from "react"; import React, { useEffect, useMemo, useRef, useState } from "react";
import styled from "styled-components"; import styled from "styled-components";
import { useFetchMetadata } from "../../contexts/fetchMetadataProvider"; import { useFetchMetadata } from "../../contexts/fetchMetadataProvider";
import { useIdentity } from "../../contexts/identityProvider"; import { useUserPublicKey } from "../../contexts/identityProvider";
import { useMessengerContext } from "../../contexts/messengerProvider"; import { useMessengerContext } from "../../contexts/messengerProvider";
import { useClickOutside } from "../../hooks/useClickOutside"; import { useClickOutside } from "../../hooks/useClickOutside";
import { ChatMessage } from "../../models/ChatMessage"; import { ChatMessage } from "../../models/ChatMessage";
@ -23,13 +22,13 @@ export function Mention({ id, setMentioned, className }: MentionProps) {
const { contacts } = useMessengerContext(); const { contacts } = useMessengerContext();
const contact = useMemo(() => contacts[id.slice(1)], [id, contacts]); const contact = useMemo(() => contacts[id.slice(1)], [id, contacts]);
const [showMenu, setShowMenu] = useState(false); const [showMenu, setShowMenu] = useState(false);
const identity = useIdentity(); const userPK = useUserPublicKey();
useEffect(() => { useEffect(() => {
if (identity && contact) { if (userPK && contact) {
if (contact.id === utils.bufToHex(identity.publicKey)) setMentioned(true); if (contact.id === userPK) setMentioned(true);
} }
}, [contact, identity]); }, [contact, userPK, setMentioned]);
const ref = useRef(null); const ref = useRef(null);
useClickOutside(ref, () => setShowMenu(false)); useClickOutside(ref, () => setShowMenu(false));
@ -92,7 +91,7 @@ export function ChatMessageContent({
newSplit.pop(); newSplit.pop();
setLink(link); setLink(link);
setElements(newSplit); setElements(newSplit);
}, [content]); }, [content, setLink, setMentioned, setElements, setLinkOpen]);
useEffect(() => { useEffect(() => {
const updatePreview = async () => { const updatePreview = async () => {
@ -108,7 +107,7 @@ export function ChatMessageContent({
} }
}; };
updatePreview(); updatePreview();
}, [link]); }, [link, fetchMetadata]);
return ( return (
<ContentWrapper> <ContentWrapper>

View File

@ -1,4 +1,4 @@
import { Picker } from "emoji-mart"; import { EmojiData, Picker } from "emoji-mart";
import React from "react"; import React from "react";
import { useTheme } from "styled-components"; import { useTheme } from "styled-components";
@ -7,7 +7,7 @@ import { lightTheme, Theme } from "../../styles/themes";
type EmojiPickerProps = { type EmojiPickerProps = {
showEmoji: boolean; showEmoji: boolean;
addEmoji: (e: any) => void; addEmoji: (e: EmojiData) => void;
bottom: number; bottom: number;
}; };

View File

@ -10,6 +10,7 @@ import { IdentityProvider } from "../contexts/identityProvider";
import { MessengerProvider } from "../contexts/messengerProvider"; import { MessengerProvider } from "../contexts/messengerProvider";
import { ModalProvider } from "../contexts/modalProvider"; import { ModalProvider } from "../contexts/modalProvider";
import { NarrowProvider } from "../contexts/narrowProvider"; import { NarrowProvider } from "../contexts/narrowProvider";
import { ScrollProvider } from "../contexts/scrollProvider";
import { ToastProvider } from "../contexts/toastProvider"; import { ToastProvider } from "../contexts/toastProvider";
import { Metadata } from "../models/Metadata"; import { Metadata } from "../models/Metadata";
import { GlobalStyle } from "../styles/GlobalStyle"; import { GlobalStyle } from "../styles/GlobalStyle";
@ -43,8 +44,10 @@ export function CommunityChat({
<IdentityProvider> <IdentityProvider>
<MessengerProvider communityKey={communityKey}> <MessengerProvider communityKey={communityKey}>
<ChatStateProvider> <ChatStateProvider>
<CommunityChatRoom /> <ScrollProvider>
<div id="modal-root" /> <CommunityChatRoom />
<div id="modal-root" />
</ScrollProvider>
</ChatStateProvider> </ChatStateProvider>
</MessengerProvider> </MessengerProvider>
</IdentityProvider> </IdentityProvider>

View File

@ -1,8 +1,7 @@
import { bufToHex } from "@waku/status-communities/dist/cjs/utils";
import React, { useMemo } from "react"; import React, { useMemo } from "react";
import styled from "styled-components"; import styled from "styled-components";
import { useIdentity } from "../../contexts/identityProvider"; import { useUserPublicKey } from "../../contexts/identityProvider";
import { useMessengerContext } from "../../contexts/messengerProvider"; import { useMessengerContext } from "../../contexts/messengerProvider";
import { useModal } from "../../contexts/modalProvider"; import { useModal } from "../../contexts/modalProvider";
import { AddContactIcon } from "../Icons/AddContactIcon"; import { AddContactIcon } from "../Icons/AddContactIcon";
@ -25,16 +24,16 @@ type ContactMenuProps = {
}; };
export function ContactMenu({ id, setShowMenu }: ContactMenuProps) { export function ContactMenu({ id, setShowMenu }: ContactMenuProps) {
const identity = useIdentity(); const userPK = useUserPublicKey();
const { contacts, contactsDispatch } = useMessengerContext(); const { contacts, contactsDispatch } = useMessengerContext();
const contact = useMemo(() => contacts[id], [id, contacts]); const contact = useMemo(() => contacts[id], [id, contacts]);
const isUser = useMemo(() => { const isUser = useMemo(() => {
if (identity) { if (userPK) {
return id === bufToHex(identity.publicKey); return id === userPK;
} else { } else {
return false; return false;
} }
}, [id, identity]); }, [id, userPK]);
const { setModal } = useModal(ProfileModalName); const { setModal } = useModal(ProfileModalName);

View File

@ -1,9 +1,8 @@
import { utils } from "@waku/status-communities/dist/cjs";
import { BaseEmoji } from "emoji-mart"; import { BaseEmoji } from "emoji-mart";
import React, { useRef } from "react"; import React, { useMemo, useRef } from "react";
import styled from "styled-components"; import styled from "styled-components";
import { useIdentity } from "../../contexts/identityProvider"; import { useUserPublicKey } from "../../contexts/identityProvider";
import { useMessengerContext } from "../../contexts/messengerProvider"; import { useMessengerContext } from "../../contexts/messengerProvider";
import { useClickOutside } from "../../hooks/useClickOutside"; import { useClickOutside } from "../../hooks/useClickOutside";
import { useClickPosition } from "../../hooks/useClickPosition"; import { useClickPosition } from "../../hooks/useClickPosition";
@ -33,23 +32,27 @@ export const MessageMenu = ({
setReply, setReply,
messageRef, messageRef,
}: MessageMenuProps) => { }: MessageMenuProps) => {
const identity = useIdentity(); const userPK = useUserPublicKey();
const { activeChannel } = useMessengerContext(); const { activeChannel } = useMessengerContext();
const { showMenu, setShowMenu } = useContextMenu(message.id); const { showMenu, setShowMenu } = useContextMenu(message.id);
const { topPosition, leftPosition } = useClickPosition(messageRef); const { topPosition, leftPosition } = useClickPosition(messageRef);
const menuStyle = { const menuStyle = useMemo(() => {
top: topPosition, return {
left: leftPosition, top: topPosition,
}; left: leftPosition,
};
}, [topPosition, leftPosition]);
const ref = useRef(null); const ref = useRef(null);
useClickOutside(ref, () => setShowMenu(false)); useClickOutside(ref, () => setShowMenu(false));
const userMessage = const userMessage = useMemo(
identity && message.sender === utils.bufToHex(identity.publicKey); () => !!userPK && message.sender === userPK,
[userPK, message]
);
return identity && showMenu ? ( return userPK && showMenu ? (
<div ref={ref} id={"messageDropdown"}> <div ref={ref} id={"messageDropdown"}>
<MessageDropdown style={menuStyle}> <MessageDropdown style={menuStyle}>
<MenuItem className="picker"> <MenuItem className="picker">

View File

@ -1,8 +1,7 @@
import { bufToHex } from "@waku/status-communities/dist/cjs/utils";
import React, { useMemo } from "react"; import React, { useMemo } from "react";
import styled from "styled-components"; import styled from "styled-components";
import { useIdentity } from "../../contexts/identityProvider"; import { useUserPublicKey } from "../../contexts/identityProvider";
import { useMessengerContext } from "../../contexts/messengerProvider"; import { useMessengerContext } from "../../contexts/messengerProvider";
import { useModal } from "../../contexts/modalProvider"; import { useModal } from "../../contexts/modalProvider";
import { Contact } from "../../models/Contact"; import { Contact } from "../../models/Contact";
@ -14,16 +13,12 @@ import { Member } from "./Member";
export function MembersList() { export function MembersList() {
const { contacts, nickname, activeChannel } = useMessengerContext(); const { contacts, nickname, activeChannel } = useMessengerContext();
const identity = useIdentity(); const userPK = useUserPublicKey();
const userPK = useMemo(
() => (identity ? bufToHex(identity?.publicKey) : undefined),
[identity]
);
const { setModal } = useModal(LogoutModalName); const { setModal } = useModal(LogoutModalName);
const members = useMemo(() => { const members = useMemo(() => {
const contactsArray = Object.values(contacts); const contactsArray = Object.values(contacts);
if (identity) { if (userPK) {
if ( if (
activeChannel && activeChannel &&
activeChannel.type === "group" && activeChannel.type === "group" &&
@ -40,7 +35,7 @@ export function MembersList() {
return contactsArray.filter((e) => e.id !== userPK); return contactsArray.filter((e) => e.id !== userPK);
} }
return contactsArray; return contactsArray;
}, [activeChannel, contacts, identity, userPK]); }, [activeChannel, contacts, userPK]);
const onlineContacts = useMemo( const onlineContacts = useMemo(
() => members.filter((e) => e.online), () => members.filter((e) => e.online),
@ -53,15 +48,15 @@ export function MembersList() {
return ( return (
<MembersListWrap> <MembersListWrap>
{identity && ( {userPK && (
<MemberCategory> <MemberCategory>
<MemberCategoryName>You</MemberCategoryName> <MemberCategoryName>You</MemberCategoryName>
<Row> <Row>
<Member <Member
contact={{ contact={{
id: userPK ?? "", id: userPK,
customName: nickname, customName: nickname,
trueName: userPK ?? "", trueName: userPK,
}} }}
isYou={true} isYou={true}
/> />

View File

@ -45,7 +45,7 @@ export function UserLogo({
return "offline"; return "offline";
} }
return ""; return "";
}, [contact]); }, [contact, showOnlineStatus]);
return ( return (
<Wrapper radius={radius} conicGradient={conicGradient}> <Wrapper radius={radius} conicGradient={conicGradient}>

View File

@ -2,7 +2,7 @@ import React from "react";
import styled from "styled-components"; import styled from "styled-components";
import { useMessengerContext } from "../../contexts/messengerProvider"; import { useMessengerContext } from "../../contexts/messengerProvider";
import { useScrollToMessage } from "../../hooks/useScrollToMessage"; import { useScrollToMessage } from "../../contexts/scrollProvider";
import { ChatMessage } from "../../models/ChatMessage"; import { ChatMessage } from "../../models/ChatMessage";
import { ReplyOn, ReplyTo } from "../Chat/ChatInput"; import { ReplyOn, ReplyTo } from "../Chat/ChatInput";
import { QuoteSvg } from "../Icons/QuoteIcon"; import { QuoteSvg } from "../Icons/QuoteIcon";

View File

@ -30,7 +30,7 @@ export function MessagesList({ setReply, channel }: MessagesListProps) {
messages.filter( messages.filter(
(message) => !contacts?.[message.sender]?.blocked ?? true (message) => !contacts?.[message.sender]?.blocked ?? true
), ),
[contacts, messages, messages.length] [contacts, messages]
); );
const [image, setImage] = useState(""); const [image, setImage] = useState("");
@ -41,8 +41,14 @@ export function MessagesList({ setReply, channel }: MessagesListProps) {
const { setModal: setLinkModal, isVisible: showLinkModal } = const { setModal: setLinkModal, isVisible: showLinkModal } =
useModal(LinkModalName); useModal(LinkModalName);
useEffect(() => (!image ? undefined : setPictureModal(true)), [image]); useEffect(
useEffect(() => (!link ? undefined : setLinkModal(true)), [link]); () => (!image ? undefined : setPictureModal(true)),
[image, setPictureModal]
);
useEffect(
() => (!link ? undefined : setLinkModal(true)),
[link, setLinkModal]
);
useEffect( useEffect(
() => (!showPictureModal ? setImage("") : undefined), () => (!showPictureModal ? setImage("") : undefined),

View File

@ -27,9 +27,9 @@ export const EditModal = () => {
const [groupName, setGroupName] = useState(""); const [groupName, setGroupName] = useState("");
const [image, setImage] = useState(""); const [image, setImage] = useState("");
const handleChange = (e: any) => { const handleChange = (e: React.FormEvent<HTMLInputElement>) => {
if (e.target.files.length) { if (e.currentTarget?.files?.length) {
setImage(URL.createObjectURL(e.target.files[0])); setImage(URL.createObjectURL(e.currentTarget.files[0]));
} }
}; };

View File

@ -1,11 +1,10 @@
import { utils } from "@waku/status-communities/dist/cjs";
import React from "react"; import React from "react";
import styled from "styled-components"; import styled from "styled-components";
import { import {
useIdentity,
useSetIdentity, useSetIdentity,
useSetNikcname, useSetNikcname,
useUserPublicKey,
} from "../../contexts/identityProvider"; } from "../../contexts/identityProvider";
import { useMessengerContext } from "../../contexts/messengerProvider"; import { useMessengerContext } from "../../contexts/messengerProvider";
import { useModal } from "../../contexts/modalProvider"; import { useModal } from "../../contexts/modalProvider";
@ -28,10 +27,10 @@ export const LogoutModal = () => {
const { setModal } = useModal(LogoutModalName); const { setModal } = useModal(LogoutModalName);
const logout = useSetIdentity(); const logout = useSetIdentity();
const setNickname = useSetNikcname(); const setNickname = useSetNikcname();
const identity = useIdentity(); const userPK = useUserPublicKey();
const { nickname } = useMessengerContext(); const { nickname } = useMessengerContext();
if (identity) { if (userPK) {
return ( return (
<Modal name={LogoutModalName}> <Modal name={LogoutModalName}>
<Section> <Section>
@ -42,9 +41,9 @@ export const LogoutModal = () => {
<UserSection> <UserSection>
<UserLogo <UserLogo
contact={{ contact={{
id: utils.bufToHex(identity.publicKey), id: userPK,
customName: nickname, customName: nickname,
trueName: utils.bufToHex(identity.publicKey), trueName: userPK,
}} }}
radius={80} radius={80}
colorWheel={[ colorWheel={[
@ -61,8 +60,8 @@ export const LogoutModal = () => {
<UserAddressWrapper className="small"> <UserAddressWrapper className="small">
<UserAddress className="small"> <UserAddress className="small">
{" "} {" "}
Chatkey: {identity.privateKey.slice(0, 10)}... Chatkey: {userPK.slice(0, 10)}...
{identity.privateKey.slice(-3)}{" "} {userPK.slice(-3)}{" "}
</UserAddress> </UserAddress>
</UserAddressWrapper> </UserAddressWrapper>
<EmojiKey className="small">🎩🍞🥑🦍🌈📡💅🏻🔔👵🅱</EmojiKey> <EmojiKey className="small">🎩🍞🥑🦍🌈📡💅🏻🔔👵🅱</EmojiKey>

View File

@ -1,8 +1,7 @@
import { bufToHex } from "@waku/status-communities/dist/cjs/utils";
import React, { useEffect, useMemo, useState } from "react"; import React, { useEffect, useMemo, useState } from "react";
import styled from "styled-components"; import styled from "styled-components";
import { useIdentity } from "../../contexts/identityProvider"; import { useUserPublicKey } from "../../contexts/identityProvider";
import { useMessengerContext } from "../../contexts/messengerProvider"; import { useMessengerContext } from "../../contexts/messengerProvider";
import { useModal } from "../../contexts/modalProvider"; import { useModal } from "../../contexts/modalProvider";
import { useToasts } from "../../contexts/toastProvider"; import { useToasts } from "../../contexts/toastProvider";
@ -51,14 +50,14 @@ export const ProfileModal = () => {
const { setToasts } = useToasts(); const { setToasts } = useToasts();
const { setModal } = useModal(ProfileModalName); const { setModal } = useModal(ProfileModalName);
const identity = useIdentity(); const userPK = useUserPublicKey();
const isUser = useMemo(() => { const isUser = useMemo(() => {
if (identity) { if (userPK) {
return id === bufToHex(identity.publicKey); return id === userPK;
} else { } else {
return false; return false;
} }
}, [id, identity]); }, [id, userPK]);
const [renaming, setRenaming] = useState(renamingState ?? false); const [renaming, setRenaming] = useState(renamingState ?? false);

View File

@ -3,9 +3,9 @@ import React, { useState } from "react";
import styled from "styled-components"; import styled from "styled-components";
import { import {
useIdentity,
useSetIdentity, useSetIdentity,
useSetNikcname, useSetNikcname,
useUserPublicKey,
useWalletIdentity, useWalletIdentity,
} from "../../contexts/identityProvider"; } from "../../contexts/identityProvider";
import { useModal } from "../../contexts/modalProvider"; import { useModal } from "../../contexts/modalProvider";
@ -38,7 +38,7 @@ export const UserCreationModalName = "UserCreationModal";
export function UserCreationModal() { export function UserCreationModal() {
const walletIdentity = useWalletIdentity(); const walletIdentity = useWalletIdentity();
const identity = useIdentity(); const userPK = useUserPublicKey();
const setIdentity = useSetIdentity(); const setIdentity = useSetIdentity();
const setNickname = useSetNikcname(); const setNickname = useSetNikcname();
@ -107,12 +107,12 @@ export function UserCreationModal() {
<NameError error={error} /> <NameError error={error} />
{nextStep && identity && ( {nextStep && userPK && (
<> <>
<UserAddress> <UserAddress>
{" "} {" "}
Chatkey: {identity.privateKey.slice(0, 10)}... Chatkey: {userPK.slice(0, 10)}...
{identity.privateKey.slice(-3)}{" "} {userPK.slice(-3)}{" "}
</UserAddress> </UserAddress>
<ChainIcons> <ChainIcons>
<ChainIcon className="transformed" /> <ChainIcon className="transformed" />

View File

@ -26,7 +26,7 @@ export function WalletModal() {
const { setModal } = useModal(WalletModalName); const { setModal } = useModal(WalletModalName);
const setIdentity = useSetIdentity(); const setIdentity = useSetIdentity();
const setWalletIdentity = useSetWalletIdentity(); const setWalletIdentity = useSetWalletIdentity();
const userCreationModal = useModal(UserCreationModalName); const { setModal: setUserCreationModal } = useModal(UserCreationModalName);
const { setModal: setWalleConnectModal } = useModal(WalletConnectModalName); const { setModal: setWalleConnectModal } = useModal(WalletConnectModalName);
const { setModal: setCoinbaseModal } = useModal(CoinbaseModalName); const { setModal: setCoinbaseModal } = useModal(CoinbaseModalName);
const { messenger } = useMessengerContext(); const { messenger } = useMessengerContext();
@ -92,7 +92,7 @@ export function WalletModal() {
setIdentity(loadedIdentity); setIdentity(loadedIdentity);
} else { } else {
setWalletIdentity(loadedIdentity); setWalletIdentity(loadedIdentity);
userCreationModal.setModal(true); setUserCreationModal(true);
} }
setModal(false); setModal(false);
return; return;
@ -102,7 +102,14 @@ export function WalletModal() {
} }
} }
alert("Metamask not found"); alert("Metamask not found");
}, [messenger]); }, [
messenger,
dappUrl,
setIdentity,
setModal,
setWalletIdentity,
setUserCreationModal,
]);
return ( return (
<Modal name={WalletModalName}> <Modal name={WalletModalName}>

View File

@ -36,7 +36,7 @@ export function ReactionPicker({
? setMessageReactions((prev) => prev.filter((e) => e != emoji)) ? setMessageReactions((prev) => prev.filter((e) => e != emoji))
: setMessageReactions((prev) => [...prev, emoji]); : setMessageReactions((prev) => [...prev, emoji]);
}, },
[messageReactions] [messageReactions, setMessageReactions]
); );
return ( return (

View File

@ -1,9 +1,8 @@
import { utils } from "@waku/status-communities/dist/cjs";
import { BaseEmoji } from "emoji-mart"; import { BaseEmoji } from "emoji-mart";
import React from "react"; import React, { useMemo } from "react";
import styled from "styled-components"; import styled from "styled-components";
import { useIdentity } from "../../contexts/identityProvider"; import { useUserPublicKey } from "../../contexts/identityProvider";
import { useMessengerContext } from "../../contexts/messengerProvider"; import { useMessengerContext } from "../../contexts/messengerProvider";
import { Reply } from "../../hooks/useReply"; import { Reply } from "../../hooks/useReply";
import { ChatMessage } from "../../models/ChatMessage"; import { ChatMessage } from "../../models/ChatMessage";
@ -28,11 +27,13 @@ export function Reactions({
messageReactions, messageReactions,
setMessageReactions, setMessageReactions,
}: ReactionsProps) { }: ReactionsProps) {
const identity = useIdentity(); const userPK = useUserPublicKey();
const { activeChannel } = useMessengerContext(); const { activeChannel } = useMessengerContext();
const userMessage = const userMessage = useMemo(
identity && message.sender === utils.bufToHex(identity.publicKey); () => !!userPK && message.sender === userPK,
[userPK, message]
);
return ( return (
<Wrapper> <Wrapper>

View File

@ -1,4 +1,4 @@
import React, { useMemo } from "react"; import React from "react";
import styled from "styled-components"; import styled from "styled-components";
import { useToasts } from "../../contexts/toastProvider"; import { useToasts } from "../../contexts/toastProvider";
@ -8,11 +8,9 @@ import { ToastMessage } from "./ToastMessage";
export function ToastMessageList() { export function ToastMessageList() {
const { toasts } = useToasts(); const { toasts } = useToasts();
const shownToasts = useMemo(() => toasts, [toasts, toasts.length]);
return ( return (
<ToastsWrapper> <ToastsWrapper>
{shownToasts.map((toast) => ( {toasts.map((toast) => (
<ToastMessage key={toast.id} toast={toast} /> <ToastMessage key={toast.id} toast={toast} />
))} ))}
</ToastsWrapper> </ToastsWrapper>

View File

@ -1,9 +1,11 @@
import { Identity } from "@waku/status-communities/dist/cjs"; import { Identity } from "@waku/status-communities/dist/cjs";
import React, { createContext, useContext, useState } from "react"; import { bufToHex } from "@waku/status-communities/dist/cjs/utils";
import React, { createContext, useContext, useMemo, useState } from "react";
const IdentityContext = createContext<{ const IdentityContext = createContext<{
identity: Identity | undefined; identity: Identity | undefined;
setIdentity: React.Dispatch<React.SetStateAction<Identity | undefined>>; setIdentity: React.Dispatch<React.SetStateAction<Identity | undefined>>;
publicKey: string | undefined;
walletIdentity: Identity | undefined; walletIdentity: Identity | undefined;
setWalletIdentity: React.Dispatch<React.SetStateAction<Identity | undefined>>; setWalletIdentity: React.Dispatch<React.SetStateAction<Identity | undefined>>;
nickname: string | undefined; nickname: string | undefined;
@ -11,6 +13,7 @@ const IdentityContext = createContext<{
}>({ }>({
identity: undefined, identity: undefined,
setIdentity: () => undefined, setIdentity: () => undefined,
publicKey: undefined,
walletIdentity: undefined, walletIdentity: undefined,
setWalletIdentity: () => undefined, setWalletIdentity: () => undefined,
nickname: undefined, nickname: undefined,
@ -21,6 +24,10 @@ export function useIdentity() {
return useContext(IdentityContext).identity; return useContext(IdentityContext).identity;
} }
export function useUserPublicKey() {
return useContext(IdentityContext).publicKey;
}
export function useSetIdentity() { export function useSetIdentity() {
return useContext(IdentityContext).setIdentity; return useContext(IdentityContext).setIdentity;
} }
@ -47,6 +54,10 @@ interface IdentityProviderProps {
export function IdentityProvider({ children }: IdentityProviderProps) { export function IdentityProvider({ children }: IdentityProviderProps) {
const [identity, setIdentity] = useState<Identity | undefined>(undefined); const [identity, setIdentity] = useState<Identity | undefined>(undefined);
const publicKey = useMemo(
() => (identity ? bufToHex(identity.publicKey) : undefined),
[identity]
);
const [walletIdentity, setWalletIdentity] = useState<Identity | undefined>( const [walletIdentity, setWalletIdentity] = useState<Identity | undefined>(
undefined undefined
); );
@ -57,6 +68,7 @@ export function IdentityProvider({ children }: IdentityProviderProps) {
value={{ value={{
identity, identity,
setIdentity, setIdentity,
publicKey,
nickname, nickname,
setNickname, setNickname,
walletIdentity, walletIdentity,

View File

@ -44,7 +44,7 @@ export function useModal<T extends string>(name: T) {
}; };
}); });
}, },
[name, modals] [name, setModals]
); );
const isVisible = useMemo(() => !!modals?.[name], [modals, name]); const isVisible = useMemo(() => !!modals?.[name], [modals, name]);

View File

@ -1,9 +1,27 @@
import { useCallback, useEffect, useState } from "react"; import React, {
createContext,
useCallback,
useContext,
useEffect,
useState,
} from "react";
import { useMessengerContext } from "../contexts/messengerProvider"; import { useMessengerContext } from "../contexts/messengerProvider";
import { ChatMessage } from "../models/ChatMessage"; import { ChatMessage } from "../models/ChatMessage";
const ScrollContext = createContext<
(msg: ChatMessage, channelId?: string) => void
>(() => undefined);
export function useScrollToMessage() { export function useScrollToMessage() {
return useContext(ScrollContext);
}
interface ScrollProviderProps {
children: React.ReactNode;
}
export function ScrollProvider({ children }: ScrollProviderProps) {
const scrollToDivId = useCallback((id: string) => { const scrollToDivId = useCallback((id: string) => {
const quoteDiv = document.getElementById(id); const quoteDiv = document.getElementById(id);
if (quoteDiv) { if (quoteDiv) {
@ -35,17 +53,18 @@ export function useScrollToMessage() {
setMessageChannel(""); setMessageChannel("");
} }
} }
}, [activeChannel, scrollToMessage, messageChannel]); }, [activeChannel, scrollToMessage, messageChannel, scrollToDivId]);
const scroll = useCallback(
const scroll = useCallback((msg: ChatMessage, channelId?: string) => { (msg: ChatMessage, channelId?: string) => {
if (!channelId) { if (!channelId || activeChannel?.id === channelId) {
scrollToDivId(msg.id); scrollToDivId(msg.id);
} else { } else {
setMessageChannel(channelId); setMessageChannel(channelId);
setScrollToMessage(msg.id); setScrollToMessage(msg.id);
channelsDispatch({ type: "ChangeActive", payload: channelId }); channelsDispatch({ type: "ChangeActive", payload: channelId });
} }
}, []); },
[scrollToDivId, channelsDispatch, activeChannel]
return scroll; );
return <ScrollContext.Provider value={scroll} children={children} />;
} }

View File

@ -101,7 +101,7 @@ export function useContacts(
const [contacts, contactsDispatch] = useReducer(contactsReducer, {}); const [contacts, contactsDispatch] = useReducer(contactsReducer, {});
const contactsClass = useMemo(() => { const contactsClass = useMemo(() => {
if (messenger) { if (messenger && messenger.identity === identity) {
const newContacts = new ContactsClass( const newContacts = new ContactsClass(
identity, identity,
messenger.waku, messenger.waku,
@ -120,7 +120,7 @@ export function useContacts(
); );
return newContacts; return newContacts;
} }
}, [messenger, identity]); }, [messenger, identity, newNickname]);
return { contacts, contactsDispatch, contactsClass, nickname }; return { contacts, contactsDispatch, contactsClass, nickname };
} }

View File

@ -84,7 +84,7 @@ export function useGroupChats(
handleMessage handleMessage
); );
} }
}, [messenger, identity, contactsClass]); }, [messenger, identity, contactsClass, addChatMessage, dispatch]);
const createGroupChat = useCallback( const createGroupChat = useCallback(
(members: string[]) => { (members: string[]) => {

View File

@ -64,7 +64,7 @@ export function useLoadPrevDay(
} }
} }
}, },
[messenger] [messenger, groupChats]
); );
return { loadingMessages, loadPrevDay }; return { loadingMessages, loadPrevDay };
} }

View File

@ -14,7 +14,9 @@ import { useNotifications } from "./useNotifications";
export function useMessages( export function useMessages(
chatId: string, chatId: string,
identity: Identity | undefined, identity: Identity | undefined,
subscriptions: ((msg: ChatMessage, id: string) => void)[], subscriptions: React.MutableRefObject<
((msg: ChatMessage, id: string) => void)[]
>,
contacts?: Contacts contacts?: Contacts
) { ) {
const [messages, setMessages] = useState<{ [chatId: string]: ChatMessage[] }>( const [messages, setMessages] = useState<{ [chatId: string]: ChatMessage[] }>(
@ -23,18 +25,22 @@ export function useMessages(
const { notifications, incNotification, clearNotifications } = const { notifications, incNotification, clearNotifications } =
useNotifications(); useNotifications();
const mentions = useNotifications(); const {
notifications: mentions,
incNotification: incMentions,
clearNotifications: clearMentions,
} = useNotifications();
const addChatMessage = useCallback( const addChatMessage = useCallback(
(newMessage: ChatMessage | undefined, id: string) => { (newMessage: ChatMessage | undefined, id: string) => {
if (newMessage) { if (newMessage) {
contacts?.addContact(newMessage.sender); contacts?.addContact(newMessage.sender);
if (newMessage.responseTo) {
newMessage.quote = messages[id].find(
(msg) => msg.id === newMessage.responseTo
);
}
setMessages((prev) => { setMessages((prev) => {
if (newMessage.responseTo && prev[id]) {
newMessage.quote = prev[id].find(
(msg) => msg.id === newMessage.responseTo
);
}
return { return {
...prev, ...prev,
[id]: binarySetInsert( [id]: binarySetInsert(
@ -45,17 +51,19 @@ export function useMessages(
), ),
}; };
}); });
subscriptions.forEach((subscription) => subscription(newMessage, id)); subscriptions.current.forEach((subscription) =>
subscription(newMessage, id)
);
incNotification(id); incNotification(id);
if ( if (
identity && identity &&
newMessage.content.includes(`@${bufToHex(identity.publicKey)}`) newMessage.content.includes(`@${bufToHex(identity.publicKey)}`)
) { ) {
mentions.incNotification(id); incMentions(id);
} }
} }
}, },
[contacts, identity, subscriptions] [contacts, identity, subscriptions, incMentions, incNotification]
); );
const addMessage = useCallback( const addMessage = useCallback(
@ -63,21 +71,23 @@ export function useMessages(
const newMessage = ChatMessage.fromMetadataMessage(msg, date); const newMessage = ChatMessage.fromMetadataMessage(msg, date);
addChatMessage(newMessage, id); addChatMessage(newMessage, id);
}, },
[contacts, identity] [addChatMessage]
); );
const activeMessages = useMemo( const activeMessages = useMemo(() => {
() => messages?.[chatId] ?? [], if (messages?.[chatId]) {
[messages, chatId] return [...messages[chatId]];
); }
return [];
}, [messages, chatId]);
return { return {
messages: activeMessages, messages: activeMessages,
addMessage, addMessage,
notifications, notifications,
clearNotifications, clearNotifications,
mentions: mentions.notifications, mentions,
clearMentions: mentions.clearNotifications, clearMentions,
addChatMessage, addChatMessage,
}; };
} }

View File

@ -6,7 +6,14 @@ import {
Identity, Identity,
Messenger, Messenger,
} from "@waku/status-communities/dist/cjs"; } from "@waku/status-communities/dist/cjs";
import { useCallback, useEffect, useMemo, useReducer, useState } from "react"; import {
useCallback,
useEffect,
useMemo,
useReducer,
useRef,
useState,
} from "react";
import { useConfig } from "../../contexts/configProvider"; import { useConfig } from "../../contexts/configProvider";
import { ChannelData, ChannelsData } from "../../models/ChannelData"; import { ChannelData, ChannelsData } from "../../models/ChannelData";
@ -60,24 +67,33 @@ function useCreateMessenger(identity: Identity | undefined) {
createMessenger(identity, environment).then((e) => { createMessenger(identity, environment).then((e) => {
setMessenger(e); setMessenger(e);
}); });
}, [identity]); }, [identity, environment]);
return messenger; return messenger;
} }
function useCreateCommunity( function useCreateCommunity(
messenger: Messenger | undefined, messenger: Messenger | undefined,
identity: Identity | undefined,
communityKey: string | undefined, communityKey: string | undefined,
addMessage: (msg: ApplicationMetadataMessage, id: string, date: Date) => void, addMessage: (msg: ApplicationMetadataMessage, id: string, date: Date) => void,
contactsClass: ContactsClass | undefined contactsClass: ContactsClass | undefined
) { ) {
const [community, setCommunity] = useState<Community | undefined>(undefined); const [community, setCommunity] = useState<Community | undefined>(undefined);
useEffect(() => { useEffect(() => {
if (messenger && communityKey && contactsClass) { if (
messenger &&
communityKey &&
contactsClass &&
addMessage &&
messenger.identity === identity
) {
createCommunity(communityKey, addMessage, messenger).then((comm) => { createCommunity(communityKey, addMessage, messenger).then((comm) => {
setCommunity(comm); setCommunity(comm);
}); });
} }
}, [messenger, communityKey, addMessage, contactsClass]); }, [messenger, communityKey, addMessage, contactsClass, identity]);
const communityData = useMemo(() => { const communityData = useMemo(() => {
if (community?.description) { if (community?.description) {
@ -101,7 +117,7 @@ function useCreateCommunity(
} else { } else {
return undefined; return undefined;
} }
}, [community]); }, [community, contactsClass]);
return { community, communityData }; return { community, communityData };
} }
@ -153,7 +169,11 @@ export function useMessenger(
subscriptionReducer, subscriptionReducer,
{} {}
); );
const subList = useMemo(() => Object.values(subscriptions), [subscriptions]); const subList = useRef<((msg: ChatMessage, id: string) => void)[]>([]);
useEffect(() => {
subList.current = Object.values(subscriptions);
}, [subscriptions]);
const [channelsState, channelsDispatch] = useChannelsReducer(); const [channelsState, channelsDispatch] = useChannelsReducer();
const messenger = useCreateMessenger(identity); const messenger = useCreateMessenger(identity);
const { contacts, contactsDispatch, contactsClass, nickname } = useContacts( const { contacts, contactsDispatch, contactsClass, nickname } = useContacts(
@ -188,6 +208,7 @@ export function useMessenger(
const { community, communityData } = useCreateCommunity( const { community, communityData } = useCreateCommunity(
messenger, messenger,
identity,
communityKey, communityKey,
addMessage, addMessage,
contactsClass contactsClass
@ -207,7 +228,7 @@ export function useMessenger(
}); });
} }
} }
}, [community]); }, [community, channelsDispatch]);
useEffect(() => { useEffect(() => {
Object.values(channelsState.channels) Object.values(channelsState.channels)
@ -227,7 +248,7 @@ export function useMessenger(
}); });
} }
}); });
}, [contacts, channelsState.channels]); }, [contacts, channelsState.channels, channelsDispatch]);
const { const {
groupChat, groupChat,
@ -255,7 +276,7 @@ export function useMessenger(
loadPrevDay(id) loadPrevDay(id)
); );
} }
}, [messenger, community]); }, [messenger, community, loadPrevDay]);
const sendMessage = useCallback( const sendMessage = useCallback(
async (messageText?: string, image?: Uint8Array, responseTo?: string) => { async (messageText?: string, image?: Uint8Array, responseTo?: string) => {
@ -299,7 +320,7 @@ export function useMessenger(
clearMentions(channelsState.activeChannel.id); clearMentions(channelsState.activeChannel.id);
} }
} }
}, [notifications, channelsState]); }, [notifications, channelsState, clearNotifications, clearMentions]);
const loadingMessenger = useMemo(() => { const loadingMessenger = useMemo(() => {
return Boolean( return Boolean(
@ -307,7 +328,7 @@ export function useMessenger(
!messenger || !messenger ||
(communityKey && !channelsState.activeChannel.id) (communityKey && !channelsState.activeChannel.id)
); );
}, [communityData, messenger, channelsState]); }, [communityData, messenger, channelsState, communityKey]);
return { return {
messenger, messenger,

View File

@ -1,7 +1,6 @@
import { bufToHex } from "@waku/status-communities/dist/cjs/utils";
import { useEffect, useMemo, useReducer } from "react"; import { useEffect, useMemo, useReducer } from "react";
import { useIdentity } from "../contexts/identityProvider"; import { useUserPublicKey } from "../contexts/identityProvider";
import { useMessengerContext } from "../contexts/messengerProvider"; import { useMessengerContext } from "../contexts/messengerProvider";
import { Activities, Activity, ActivityStatus } from "../models/Activity"; import { Activities, Activity, ActivityStatus } from "../models/Activity";
import { ChatMessage } from "../models/ChatMessage"; import { ChatMessage } from "../models/ChatMessage";
@ -65,17 +64,13 @@ export function useActivities() {
() => Object.values(activitiesObj), () => Object.values(activitiesObj),
[activitiesObj] [activitiesObj]
); );
const identity = useIdentity(); const userPK = useUserPublicKey();
const userPK = useMemo(
() => (identity ? bufToHex(identity.publicKey) : undefined),
[identity]
);
const { subscriptionsDispatch, channels } = useMessengerContext(); const { subscriptionsDispatch, channels } = useMessengerContext();
useEffect(() => { useEffect(() => {
if (identity) { if (userPK) {
const subscribeFunction = (message: ChatMessage, id: string) => { const subscribeFunction = (message: ChatMessage, id: string) => {
if (message.quote && identity && message.quote.sender === userPK) { if (message.quote && message.quote.sender === userPK) {
const newActivity: Activity = { const newActivity: Activity = {
id: message.date.getTime().toString() + message.content, id: message.date.getTime().toString() + message.content,
type: "reply", type: "reply",
@ -114,7 +109,7 @@ export function useActivities() {
type: "removeSubscription", type: "removeSubscription",
payload: { name: "activityCenter" }, payload: { name: "activityCenter" },
}); });
}, [subscriptionsDispatch, identity]); }, [subscriptionsDispatch, userPK, channels]);
return { activities, activityDispatch: dispatch }; return { activities, activityDispatch: dispatch };
} }

View File

@ -14,10 +14,10 @@ export function useChatScrollHandle(
if (ref && ref.current && scrollOnBot) { if (ref && ref.current && scrollOnBot) {
ref.current.scrollTop = ref.current.scrollHeight; ref.current.scrollTop = ref.current.scrollHeight;
} }
}, [messages.length, scrollOnBot]); }, [messages.length, scrollOnBot, ref]);
useEffect(() => { useEffect(() => {
if (!loadingMessages && activeChannel) { if (activeChannel) {
if ( if (
(ref?.current?.clientHeight ?? 0) >= (ref?.current?.scrollHeight ?? 0) (ref?.current?.clientHeight ?? 0) >= (ref?.current?.scrollHeight ?? 0)
) { ) {
@ -25,9 +25,10 @@ export function useChatScrollHandle(
loadPrevDay(activeChannel.id, activeChannel.type !== "channel"); loadPrevDay(activeChannel.id, activeChannel.type !== "channel");
} }
} }
}, [messages.length, activeChannel]); }, [messages.length, activeChannel, loadPrevDay, setScrollOnBot, ref]);
useEffect(() => { useEffect(() => {
const currentRef = ref.current;
const setScroll = () => { const setScroll = () => {
if (ref?.current && activeChannel) { if (ref?.current && activeChannel) {
if (ref.current.scrollTop <= 0) { if (ref.current.scrollTop <= 0) {
@ -47,8 +48,8 @@ export function useChatScrollHandle(
} }
} }
}; };
ref.current?.addEventListener("scroll", setScroll); currentRef?.addEventListener("scroll", setScroll);
return () => ref.current?.removeEventListener("scroll", setScroll); return () => currentRef?.removeEventListener("scroll", setScroll);
}, [ref, scrollOnBot, activeChannel]); }, [ref, scrollOnBot, activeChannel, loadPrevDay]);
return loadingMessages; return loadingMessages;
} }

View File

@ -2,8 +2,7 @@ import { RefObject, useCallback, useEffect } from "react";
export const useClickOutside = ( export const useClickOutside = (
ref: RefObject<HTMLDivElement>, ref: RefObject<HTMLDivElement>,
callback: () => void, callback: () => void
deps?: any[]
) => { ) => {
const handleClick = useCallback( const handleClick = useCallback(
(e: MouseEvent) => { (e: MouseEvent) => {
@ -20,5 +19,5 @@ export const useClickOutside = (
return () => { return () => {
document.removeEventListener("mousedown", handleClick); document.removeEventListener("mousedown", handleClick);
}; };
}, deps); }, [handleClick]);
}; };

View File

@ -15,7 +15,7 @@ export const useClickPosition = (ref: RefObject<HTMLDivElement>) => {
setTopPosition(imgTarget ? 0 : e.clientY - rect.top); setTopPosition(imgTarget ? 0 : e.clientY - rect.top);
} }
}, },
[setTopPosition, setLeftPosition] [setTopPosition, setLeftPosition, ref]
); );
useEffect(() => { useEffect(() => {

View File

@ -21,7 +21,7 @@ export const useContextMenu = (elementId: string) => {
document.removeEventListener("click", () => setShowMenu(false)); document.removeEventListener("click", () => setShowMenu(false));
setShowMenu(false); setShowMenu(false);
}; };
}, [elementId]); }, [elementId, handleContextMenu]);
return { showMenu, setShowMenu }; return { showMenu, setShowMenu };
}; };

View File

@ -12,9 +12,9 @@ export enum NameErrors {
export function useNameError(name: string) { export function useNameError(name: string) {
const { contacts } = useMessengerContext(); const { contacts } = useMessengerContext();
const RegName = new RegExp("^[a-z0-9_-]+$");
const error = useMemo(() => { const error = useMemo(() => {
const RegName = new RegExp("^[a-z0-9_-]+$");
if (name === "") { if (name === "") {
return NameErrors.NoError; return NameErrors.NoError;
} }

View File

@ -20,7 +20,7 @@ export function useRefBreak(dimension: number, sizeThreshold: number) {
return () => { return () => {
window.removeEventListener("resize", checkDimensions); window.removeEventListener("resize", checkDimensions);
}; };
}, [dimension, widthBreak]); }, [dimension, widthBreak, sizeThreshold]);
return widthBreak; return widthBreak;
} }