From bf7c15bc290080e366d0b6655c5c4449c2b5ef0c Mon Sep 17 00:00:00 2001 From: Szymon Szlachtowicz <38212223+Szymx95@users.noreply.github.com> Date: Thu, 3 Feb 2022 08:57:05 +0100 Subject: [PATCH] Fix hook problems (#216) --- .../ActivityCenter/ActivityCenter.tsx | 2 +- .../ActivityCenter/ActivityMessage.tsx | 7 +- .../src/components/Channels/EmptyChannel.tsx | 15 ++- .../src/components/Chat/ChatBody.tsx | 26 ++--- .../src/components/Chat/ChatCreation.tsx | 89 +++++++++-------- .../src/components/Chat/ChatInput.tsx | 95 ++++++++++++------- .../components/Chat/ChatMessageContent.tsx | 15 ++- .../src/components/Chat/EmojiPicker.tsx | 4 +- .../src/components/CommunityChat.tsx | 7 +- .../src/components/Form/ContactMenu.tsx | 11 +-- .../src/components/Form/MessageMenu.tsx | 25 ++--- .../src/components/Members/MembersList.tsx | 19 ++-- .../src/components/Members/UserLogo.tsx | 2 +- .../src/components/Messages/MessageQuote.tsx | 2 +- .../src/components/Messages/MessagesList.tsx | 12 ++- .../src/components/Modals/EditModal.tsx | 6 +- .../src/components/Modals/LogoutModal.tsx | 15 ++- .../src/components/Modals/ProfileModal.tsx | 11 +-- .../components/Modals/UserCreationModal.tsx | 10 +- .../src/components/Modals/WalletModal.tsx | 13 ++- .../components/Reactions/ReactionPicker.tsx | 2 +- .../src/components/Reactions/Reactions.tsx | 13 +-- .../ToastMessages/ToastMessageList.tsx | 6 +- .../src/contexts/identityProvider.tsx | 14 ++- .../react-chat/src/contexts/modalProvider.tsx | 2 +- .../scrollProvider.tsx} | 47 ++++++--- .../src/hooks/messenger/useContacts.ts | 4 +- .../src/hooks/messenger/useGroupChats.ts | 2 +- .../src/hooks/messenger/useLoadPrevDay.ts | 2 +- .../src/hooks/messenger/useMessages.ts | 44 +++++---- .../src/hooks/messenger/useMessenger.ts | 43 ++++++--- .../react-chat/src/hooks/useActivities.ts | 15 +-- .../src/hooks/useChatScrollHandle.ts | 13 +-- .../react-chat/src/hooks/useClickOutside.ts | 5 +- .../react-chat/src/hooks/useClickPosition.ts | 2 +- .../react-chat/src/hooks/useContextMenu.ts | 2 +- .../react-chat/src/hooks/useNameError.tsx | 2 +- packages/react-chat/src/hooks/useRefBreak.ts | 2 +- 38 files changed, 354 insertions(+), 252 deletions(-) rename packages/react-chat/src/{hooks/useScrollToMessage.ts => contexts/scrollProvider.tsx} (55%) diff --git a/packages/react-chat/src/components/ActivityCenter/ActivityCenter.tsx b/packages/react-chat/src/components/ActivityCenter/ActivityCenter.tsx index d35f724f..5c18c8d3 100644 --- a/packages/react-chat/src/components/ActivityCenter/ActivityCenter.tsx +++ b/packages/react-chat/src/components/ActivityCenter/ActivityCenter.tsx @@ -30,7 +30,7 @@ export function ActivityCenter({ activities.filter( (activity) => !contacts?.[activity.user]?.blocked ?? true ), - [contacts, activities, activities.length] + [contacts, activities] ); const [hideRead, setHideRead] = useState(false); diff --git a/packages/react-chat/src/components/ActivityCenter/ActivityMessage.tsx b/packages/react-chat/src/components/ActivityCenter/ActivityMessage.tsx index 0d26fbc3..455e8a92 100644 --- a/packages/react-chat/src/components/ActivityCenter/ActivityMessage.tsx +++ b/packages/react-chat/src/components/ActivityCenter/ActivityMessage.tsx @@ -3,9 +3,9 @@ import styled from "styled-components"; import { useMessengerContext } from "../../contexts/messengerProvider"; import { useModal } from "../../contexts/modalProvider"; +import { useScrollToMessage } from "../../contexts/scrollProvider"; import { ActivityAction } from "../../hooks/useActivities"; import { useClickOutside } from "../../hooks/useClickOutside"; -import { useScrollToMessage } from "../../hooks/useScrollToMessage"; import { Activity } from "../../models/Activity"; import { equalDate } from "../../utils/equalDate"; import { DownloadButton } from "../Buttons/DownloadButton"; @@ -169,7 +169,10 @@ export function ActivityMessage({ {"message" in activity && activity.message?.content && (
scroll(activity.message, activity.channel.id)} + onClick={() => { + scroll(activity.message, activity.channel.id); + setShowActivityCenter(false); + }} > {elements.map((el) => el)}
diff --git a/packages/react-chat/src/components/Channels/EmptyChannel.tsx b/packages/react-chat/src/components/Channels/EmptyChannel.tsx index e7c94817..2af55a36 100644 --- a/packages/react-chat/src/components/Channels/EmptyChannel.tsx +++ b/packages/react-chat/src/components/Channels/EmptyChannel.tsx @@ -1,8 +1,7 @@ -import { utils } from "@waku/status-communities/dist/cjs"; import React, { useMemo } from "react"; import styled from "styled-components"; -import { useIdentity } from "../../contexts/identityProvider"; +import { useUserPublicKey } from "../../contexts/identityProvider"; import { useMessengerContext } from "../../contexts/messengerProvider"; import { useNarrow } from "../../contexts/narrowProvider"; import { ChannelData } from "../../models/ChannelData"; @@ -16,17 +15,16 @@ type ChannelBeggingTextProps = { }; function ChannelBeggingText({ channel }: ChannelBeggingTextProps) { - const identity = useIdentity(); + const userPK = useUserPublicKey(); const { contacts } = useMessengerContext(); const members = useMemo(() => { - if (channel?.members && identity) { - const publicKey = utils.bufToHex(identity.publicKey); + if (channel?.members && userPK) { return channel.members - .filter((contact) => contact.id !== publicKey) + .filter((contact) => contact.id !== userPK) .map((member) => contacts?.[member.id] ?? member); } return []; - }, [channel, contacts]); + }, [channel, contacts, userPK]); switch (channel.type) { case "dm": @@ -40,8 +38,7 @@ function ChannelBeggingText({ channel }: ChannelBeggingTextProps) { case "group": return ( - {identity && {utils.bufToHex(identity.publicKey)}}{" "} - created a group with{" "} + {userPK && {userPK}} created a group with{" "} {members.map((contact, idx) => ( {contact?.customName ?? contact.trueName.slice(0, 10)} diff --git a/packages/react-chat/src/components/Chat/ChatBody.tsx b/packages/react-chat/src/components/Chat/ChatBody.tsx index 5dcb7b7e..a83fea70 100644 --- a/packages/react-chat/src/components/Chat/ChatBody.tsx +++ b/packages/react-chat/src/components/Chat/ChatBody.tsx @@ -116,19 +116,21 @@ export function ChatBody({ activeChannel={activeChannel} /> ) : ( - + <> + + + )} - {!permission && ( diff --git a/packages/react-chat/src/components/Chat/ChatCreation.tsx b/packages/react-chat/src/components/Chat/ChatCreation.tsx index 5a2bc9ac..7ecd0666 100644 --- a/packages/react-chat/src/components/Chat/ChatCreation.tsx +++ b/packages/react-chat/src/components/Chat/ChatCreation.tsx @@ -1,9 +1,8 @@ -import { bufToHex } from "@waku/status-communities/dist/cjs/utils"; -import React, { useCallback, useState } from "react"; +import React, { useCallback, useMemo, useState } from "react"; import styled from "styled-components"; import { ChatState, useChatState } from "../../contexts/chatStateProvider"; -import { useIdentity } from "../../contexts/identityProvider"; +import { useUserPublicKey } from "../../contexts/identityProvider"; import { useMessengerContext } from "../../contexts/messengerProvider"; import { useNarrow } from "../../contexts/narrowProvider"; import { ChannelData } from "../../models/ChannelData"; @@ -27,19 +26,23 @@ export function ChatCreation({ activeChannel, }: ChatCreationProps) { const narrow = useNarrow(); - const identity = useIdentity(); + const userPK = useUserPublicKey(); const [query, setQuery] = useState(""); - const [styledGroup, setStyledGroup] = useState( - activeChannel?.members?.map( - (member) => member?.customName ?? member.trueName - ) ?? [] + const [groupChatMembersIds, setGroupChatMembersIds] = useState( + activeChannel?.members?.map((member) => member.id) ?? [] ); const { contacts, createGroupChat, addMembers } = useMessengerContext(); + + const groupChatMembers = useMemo( + () => groupChatMembersIds.map((id) => contacts[id]).filter((e) => !!e), + [groupChatMembersIds, contacts] + ); + const setChatState = useChatState()[1]; const addMember = useCallback( (member: string) => { - setStyledGroup((prevMembers: string[]) => { + setGroupChatMembersIds((prevMembers: string[]) => { if ( prevMembers.find((mem) => mem === member) || prevMembers.length >= 5 @@ -50,33 +53,44 @@ export function ChatCreation({ } }); setQuery(""); - if (activeChannel) addMembers(styledGroup, activeChannel.id); }, - [setStyledGroup, styledGroup] + [setGroupChatMembersIds] ); const removeMember = useCallback( (member: string) => { - setStyledGroup((prev) => prev.filter((e) => e != member)); + setGroupChatMembersIds((prev) => prev.filter((e) => e != member)); }, - [setStyledGroup] + [setGroupChatMembersIds] ); const createChat = useCallback( (group: string[]) => { - if (identity) { + if (userPK) { const newGroup = group.slice(); - newGroup.push(bufToHex(identity.publicKey)); + newGroup.push(userPK); createGroupChat(newGroup); 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 ( {narrow && ( To: - {styledGroup.map((member) => ( - - {member.slice(0, 10)} - removeMember(member)}> + {groupChatMembers.map((member) => ( + + + {member?.customName?.slice(0, 10) ?? + member.trueName.slice(0, 10)} + + removeMember(member.id)}> ))} - {styledGroup.length < 5 && ( + {groupChatMembers.length < 5 && ( )} - {!narrow && styledGroup.length === 5 && ( + {!narrow && groupChatMembers.length === 5 && ( 5 user Limit reached )} - {narrow && styledGroup.length === 5 && ( + {narrow && groupChatMembers.length === 5 && ( 5 user Limit reached )} { - if (!activeChannel) { - createChat(styledGroup); - } else { - addMembers(styledGroup, activeChannel.id); - } - setEditGroup?.(false); - }} + disabled={groupChatMembers.length === 0} + onClick={handleCreationClick} > Confirm {!narrow && } @@ -137,13 +147,11 @@ export function ChatCreation({ Contacts - {identity && + {userPK && !query && Object.values(contacts) .filter( - (e) => - e.id != bufToHex(identity.publicKey) && - !styledGroup.includes(e.id) + (e) => e.id != userPK && !groupChatMembersIds.includes(e.id) ) .map((contact) => ( )} {!activeChannel && ( - + member.id)} + /> )} ); diff --git a/packages/react-chat/src/components/Chat/ChatInput.tsx b/packages/react-chat/src/components/Chat/ChatInput.tsx index c6da76aa..fb90817d 100644 --- a/packages/react-chat/src/components/Chat/ChatInput.tsx +++ b/packages/react-chat/src/components/Chat/ChatInput.tsx @@ -1,3 +1,4 @@ +import { EmojiData } from "emoji-mart"; import React, { useCallback, useEffect, @@ -72,16 +73,23 @@ export function ChatInput({ [imageUint] ); - const addEmoji = useCallback((e: any) => { - const sym = e.unified.split("-"); - const codesArray: any[] = []; - sym.forEach((el: string) => codesArray.push("0x" + el)); - const emoji = String.fromCodePoint(...codesArray); - if (inputRef.current) { - inputRef.current.appendChild(document.createTextNode(emoji)); - } - setContent((p) => p + emoji); - }, []); + const addEmoji = useCallback( + (e: EmojiData) => { + if ("unified" in e) { + const sym = e.unified.split("-"); + const codesArray: string[] = []; + sym.forEach((el: string) => codesArray.push("0x" + el)); + const emoji = String.fromCodePoint( + ...(codesArray as unknown as number[]) + ); + if (inputRef.current) { + inputRef.current.appendChild(document.createTextNode(emoji)); + } + setContent((p) => p + emoji); + } + }, + [setContent] + ); const resizeTextArea = useCallback((target: HTMLDivElement) => { target.style.height = "40px"; @@ -91,31 +99,37 @@ export function ChatInput({ const rowHeight = inputHeight + (image ? 73 : 0); - const onInputChange = useCallback((e: React.ChangeEvent) => { - const element = document.getSelection(); - const inputElement = inputRef.current; - if (inputElement && element && element.rangeCount > 0) { - const selection = element?.getRangeAt(0)?.startOffset; - const parentElement = element.anchorNode?.parentElement; - if (parentElement && parentElement.tagName === "B") { - parentElement.outerHTML = parentElement.innerText; - const range = document.createRange(); - const sel = window.getSelection(); - if (element.anchorNode.firstChild) { - const childNumber = - element.focusOffset === 0 ? 0 : element.focusOffset - 1; - range.setStart(element.anchorNode.childNodes[childNumber], selection); - } - range.collapse(true); + const onInputChange = useCallback( + (e: React.ChangeEvent) => { + const element = document.getSelection(); + const inputElement = inputRef.current; + if (inputElement && element && element.rangeCount > 0) { + const selection = element?.getRangeAt(0)?.startOffset; + const parentElement = element.anchorNode?.parentElement; + if (parentElement && parentElement.tagName === "B") { + parentElement.outerHTML = parentElement.innerText; + const range = document.createRange(); + const sel = window.getSelection(); + if (element.anchorNode.firstChild) { + const childNumber = + element.focusOffset === 0 ? 0 : element.focusOffset - 1; + range.setStart( + element.anchorNode.childNodes[childNumber], + selection + ); + } + range.collapse(true); - sel?.removeAllRanges(); - sel?.addRange(range); + sel?.removeAllRanges(); + sel?.addRange(range); + } } - } - const target = e.target; - resizeTextArea(target); - setContent(target.textContent ?? ""); - }, []); + const target = e.target; + resizeTextArea(target); + setContent(target.textContent ?? ""); + }, + [resizeTextArea] + ); const onInputKeyPress = useCallback( (e: React.KeyboardEvent) => { @@ -137,7 +151,16 @@ export function ChatInput({ } } }, - [content, imageUint] + [ + content, + imageUint, + createChat, + group, + sendMessage, + reply?.id, + setChatState, + setReply, + ] ); const [selectedElement, setSelectedElement] = useState<{ @@ -176,7 +199,7 @@ export function ChatInput({ } }, []); - useEffect(handleCursorChange, [content]); + useEffect(handleCursorChange, [content, handleCursorChange]); const addMention = useCallback( (contact: string) => { @@ -215,7 +238,7 @@ export function ChatInput({ } } }, - [inputRef, inputRef?.current, content, selectedElement] + [inputRef, content, selectedElement, resizeTextArea] ); return ( diff --git a/packages/react-chat/src/components/Chat/ChatMessageContent.tsx b/packages/react-chat/src/components/Chat/ChatMessageContent.tsx index b620890c..87e4bf6a 100644 --- a/packages/react-chat/src/components/Chat/ChatMessageContent.tsx +++ b/packages/react-chat/src/components/Chat/ChatMessageContent.tsx @@ -1,10 +1,9 @@ -import { utils } from "@waku/status-communities/dist/cjs"; import { decode } from "html-entities"; import React, { useEffect, useMemo, useRef, useState } from "react"; import styled from "styled-components"; import { useFetchMetadata } from "../../contexts/fetchMetadataProvider"; -import { useIdentity } from "../../contexts/identityProvider"; +import { useUserPublicKey } from "../../contexts/identityProvider"; import { useMessengerContext } from "../../contexts/messengerProvider"; import { useClickOutside } from "../../hooks/useClickOutside"; import { ChatMessage } from "../../models/ChatMessage"; @@ -23,13 +22,13 @@ export function Mention({ id, setMentioned, className }: MentionProps) { const { contacts } = useMessengerContext(); const contact = useMemo(() => contacts[id.slice(1)], [id, contacts]); const [showMenu, setShowMenu] = useState(false); - const identity = useIdentity(); + const userPK = useUserPublicKey(); useEffect(() => { - if (identity && contact) { - if (contact.id === utils.bufToHex(identity.publicKey)) setMentioned(true); + if (userPK && contact) { + if (contact.id === userPK) setMentioned(true); } - }, [contact, identity]); + }, [contact, userPK, setMentioned]); const ref = useRef(null); useClickOutside(ref, () => setShowMenu(false)); @@ -92,7 +91,7 @@ export function ChatMessageContent({ newSplit.pop(); setLink(link); setElements(newSplit); - }, [content]); + }, [content, setLink, setMentioned, setElements, setLinkOpen]); useEffect(() => { const updatePreview = async () => { @@ -108,7 +107,7 @@ export function ChatMessageContent({ } }; updatePreview(); - }, [link]); + }, [link, fetchMetadata]); return ( diff --git a/packages/react-chat/src/components/Chat/EmojiPicker.tsx b/packages/react-chat/src/components/Chat/EmojiPicker.tsx index 3c236d26..eb424031 100644 --- a/packages/react-chat/src/components/Chat/EmojiPicker.tsx +++ b/packages/react-chat/src/components/Chat/EmojiPicker.tsx @@ -1,4 +1,4 @@ -import { Picker } from "emoji-mart"; +import { EmojiData, Picker } from "emoji-mart"; import React from "react"; import { useTheme } from "styled-components"; @@ -7,7 +7,7 @@ import { lightTheme, Theme } from "../../styles/themes"; type EmojiPickerProps = { showEmoji: boolean; - addEmoji: (e: any) => void; + addEmoji: (e: EmojiData) => void; bottom: number; }; diff --git a/packages/react-chat/src/components/CommunityChat.tsx b/packages/react-chat/src/components/CommunityChat.tsx index 28bcc8c4..7a65c5bc 100644 --- a/packages/react-chat/src/components/CommunityChat.tsx +++ b/packages/react-chat/src/components/CommunityChat.tsx @@ -10,6 +10,7 @@ import { IdentityProvider } from "../contexts/identityProvider"; import { MessengerProvider } from "../contexts/messengerProvider"; import { ModalProvider } from "../contexts/modalProvider"; import { NarrowProvider } from "../contexts/narrowProvider"; +import { ScrollProvider } from "../contexts/scrollProvider"; import { ToastProvider } from "../contexts/toastProvider"; import { Metadata } from "../models/Metadata"; import { GlobalStyle } from "../styles/GlobalStyle"; @@ -43,8 +44,10 @@ export function CommunityChat({ - -