From 592e32998ff383589783893d381b113dc1a575f3 Mon Sep 17 00:00:00 2001 From: coderboy-yash <109899959+coderboy-yash@users.noreply.github.com> Date: Thu, 17 Aug 2023 22:46:11 +0530 Subject: [PATCH 01/12] changes made to readme.md and added steps for windows (#225) * Updated README.md * added screenshot to README.md * ss corrected README.md * added steps for windows user in README.md * added installation steps for windows users * removed some errors README.md * added mock image to README.md --- README.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4e538812c..284099729 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ -# EmbeddedChat +

Embedded chat: A staple in excellent customer service

+ +![image](https://github.com/coderboy-yash/EmbeddedChat/assets/109899959/b2961a35-4300-48df-b674-8a128c73e838) + An easy to use full-stack component (ReactJS + backend behaviors) embedding Rocket.Chat into your webapp. @@ -12,6 +15,14 @@ _EmbeddedChat is a full-stack React component node module of the RocketChat appl +## Wiki and FAQs +Check out our [Wiki](https://github.com/RocketChat/EmbeddedChat/wiki) and [FAQ](https://github.com/RocketChat/EmbeddedChat/wiki/FAQs) page for in-depth guides and answers to common questions. Whether you're a newbie or an expert, you'll find valuable insights to enhance your experience. + +![image](https://github.com/coderboy-yash/EmbeddedChat/assets/109899959/af6ea4b4-8499-4f9d-aa83-56c2cf8123c8) + +## Understanding the Internals +For those of you who love diving into the technical details, we have a [Roots of EmbeddedChat wiki](https://github.com/RocketChat/EmbeddedChat/wiki/Roots-of-EmbeddedChat) that delves into the project's internals. Gain a deeper understanding of how everything works behind the scenes and unlock the full potential of the project. + ## Installation ```bash @@ -63,7 +74,9 @@ Read this [wiki page](https://github.com/RocketChat/EmbeddedChat/wiki/Roots-of-E | anonymousMode | if the user can see the chat without logging in | | showAvatar | show the user's avatar in the chat component, defaults to false | | showRoles | show the user's roles in the chat component, defaults to false | -| enableThreads | enable RocketChat's style thread messages, defaults to false | +| enableThreads | enable RocketChat's style thread messages, defaults to false | +| headerColor | sets the background color of the chat header, providing visual customization.| +| toastBarPosition | defines where the toast bar appears in the chat interface, allowing you to control its position for better user experience.| ## Setting up Authentication @@ -80,13 +93,49 @@ npm run dev # at the root folder --> EMBEDDEDCHAT ``` + + It will open up a playground react app at `http://localhost:4000`. Make a `.env` file in the playground directory following the `.env[example]` file. +### Setup for `Windows` user + +Above command might not work if you are a `Windows`user because in package.json the scripts are written according to Linux environment so do these steps :- +```bash +step 1:- clone the forked repo in your vs code +step 2:- go to EmbeddedChat -> package.json + change + "scripts":{ + "build": "NODE_ENV=development rollup -c --context=window", + "build:prod": "NODE_ENV=production rollup -c --context=window", + } + to ------> + "scripts":{ + "build": "set NODE_ENV=development && rollup -c --context=window", + "build:prod": "set NODE_ENV=production && rollup -c --context=window", + + } +step 3:- go to embeddedChat -> playground->package.json + change + "scripts":{ + "start": "PORT=4000 node ../node_modules/react-scripts/bin/react-scripts.js start", + } + to ------> + "scripts":{ + "start": " set PORT=4000 && node ../node_modules/react-scripts/bin/react-scripts.js start", + } + + + +``` +### note +if `npm i` gives error try `npm i --legacy-peer`and error might be solved.

Gitpod Setup

Make a `.env` file in the playground directory following the `.env[example]` file. + + Date: Fri, 16 Feb 2024 22:28:58 +0530 Subject: [PATCH 02/12] fixed logout issue - auth Headers were not set (#462) --- packages/auth/src/Api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/auth/src/Api.ts b/packages/auth/src/Api.ts index d124efe0a..7179a4e09 100644 --- a/packages/auth/src/Api.ts +++ b/packages/auth/src/Api.ts @@ -33,7 +33,7 @@ export class Api { body: data ? JSON.stringify(data) : undefined, method, headers: { - 'Content-Type': 'application/json' + ...config.headers, } }); if (!response.ok) { From 449b52ea287580d9c7dc2fddb407e20a5d189a88 Mon Sep 17 00:00:00 2001 From: Zishan Ahmad Date: Fri, 16 Feb 2024 22:31:47 +0530 Subject: [PATCH 03/12] fix: Back Button Inconsistency in Threads and Starred/Pinned Sections. (#460) * fixed location of back icon created custom reusable hook to fetch chat data from different components changed dynamic header parameters to include both back icon and header icons removed back-arrow-icon from chatbody * formatted the changed files using prettier fixed linting issues of which i could understand and have worked before --- .../src/components/AllThreads/AllThreads.js | 237 ++++++++++-------- .../react/src/components/ChatBody/ChatBody.js | 89 ++----- .../src/components/ChatHeader/ChatHeader.js | 104 +++++--- .../components/DynamicHeader/DynamicHeader.js | 53 ++-- packages/react/src/components/EmbeddedChat.js | 30 ++- .../src/components/MessageList/MessageList.js | 17 +- packages/react/src/hooks/useFetchChatData.js | 76 ++++++ 7 files changed, 350 insertions(+), 256 deletions(-) create mode 100644 packages/react/src/hooks/useFetchChatData.js diff --git a/packages/react/src/components/AllThreads/AllThreads.js b/packages/react/src/components/AllThreads/AllThreads.js index 24a56dc02..389b5034b 100644 --- a/packages/react/src/components/AllThreads/AllThreads.js +++ b/packages/react/src/components/AllThreads/AllThreads.js @@ -4,14 +4,17 @@ import classes from './AllThreads.module.css'; import { Icon } from '../Icon'; import { Box } from '../Box'; import { ActionButton } from '../ActionButton'; -import { useMessageStore, useUserStore, useThreadsMessageStore } from '../../store'; +import { + useMessageStore, + useUserStore, + useThreadsMessageStore, +} from '../../store'; import { MessageBody } from '../Message/MessageBody'; import { MessageMetrics } from '../Message/MessageMetrics'; import MessageAvatarContainer from '../Message/MessageAvatarContainer'; import MessageBodyContainer from '../Message/MessageBodyContainer'; import MessageHeader from '../Message/MessageHeader'; - const MessageCss = css` display: flex; flex-direction: row; @@ -32,118 +35,146 @@ const MessageCss = css` `; const AllThreads = () => { - const showAvatar = useUserStore((state) => state.showAvatar); - const messages = useMessageStore((state) => state.messages); - const setShowAllThreads = useThreadsMessageStore((state) => state.setShowAllThreads); - const openThread = useMessageStore((state) => state.openThread); - const [text, setText] = useState(''); + const showAvatar = useUserStore((state) => state.showAvatar); + const messages = useMessageStore((state) => state.messages); + const setShowAllThreads = useThreadsMessageStore( + (state) => state.setShowAllThreads + ); + const openThread = useMessageStore((state) => state.openThread); + const [text, setText] = useState(''); - const toggleShowAllThreads = () => { - setShowAllThreads(false); - }; + const toggleShowAllThreads = () => { + setShowAllThreads(false); + }; - const handleOpenThread = (msg) => () => { - openThread(msg); - toggleShowAllThreads(false); - }; + const handleOpenThread = (msg) => () => { + openThread(msg); + toggleShowAllThreads(false); + }; - const handleInputChange = (e) => { - setText(e.target.value); - }; + const handleInputChange = (e) => { + setText(e.target.value); + }; - const filteredThreads = useMemo(() => { - return messages.filter((message) => - message.msg.toLowerCase().includes(text.toLowerCase()) - ); - }, [messages, text]); + const filteredThreads = useMemo( + () => + messages.filter((message) => + message.msg.toLowerCase().includes(text.toLowerCase()) + ), + [messages, text] + ); - return ( - - + return ( + + + + +

+ + + Threads + + + + +

+
- - -

- - - Threads - - - - -

-
+ + - - + + + - -
-
+ + {filteredThreads.length === 0 ? ( + + + + No threads found + + + ) : ( + filteredThreads.map( + (message) => + !message.t && + message.tcount && ( + + {showAvatar && ( + + )} + + - - {filteredThreads.length === 0 ? ( - - - No threads found - - ) : (filteredThreads - .map((message) => ( - !message.t && message.tcount && ( - - {showAvatar && ( - - )} - - {} - - {message.attachments && message.attachments.length > 0 ? ( - message.file.name - ) : ( - message.msg - )} - + + {message.attachments && message.attachments.length > 0 + ? message.file.name + : message.msg} + - - - - ) - )))} - - + + + + ) + ) + )}
- ); +
+
+ ); }; export default AllThreads; diff --git a/packages/react/src/components/ChatBody/ChatBody.js b/packages/react/src/components/ChatBody/ChatBody.js index 002f8890a..90d26e126 100644 --- a/packages/react/src/components/ChatBody/ChatBody.js +++ b/packages/react/src/components/ChatBody/ChatBody.js @@ -13,8 +13,15 @@ import ThreadMessageList from '../Thread/ThreadMessageList'; import ModalBlock from '../uiKit/blocks/ModalBlock'; import useComponentOverrides from '../../theme/useComponentOverrides'; import RecentMessageButton from './RecentMessageButton'; - -const ChatBody = ({ height, anonymousMode, showRoles, scrollToBottom, messageListRef }) => { +import useFetchChatData from '../../hooks/useFetchChatData'; + +const ChatBody = ({ + height, + anonymousMode, + showRoles, + scrollToBottom, + messageListRef, +}) => { const { classNames, styleOverrides } = useComponentOverrides('ChatBody'); const ChatBodyCss = css` word-break: break-all; @@ -46,12 +53,9 @@ const ChatBody = ({ height, anonymousMode, showRoles, scrollToBottom, messageLis const messages = useMessageStore((state) => state.messages); const threadMessages = useMessageStore((state) => state.threadMessages); - const setMessages = useMessageStore((state) => state.setMessages); const setThreadMessages = useMessageStore((state) => state.setThreadMessages); const upsertMessage = useMessageStore((state) => state.upsertMessage); const removeMessage = useMessageStore((state) => state.removeMessage); - const setFilter = useMessageStore((state) => state.setFilter); - const setRoles = useUserStore((state) => state.setRoles); const isChannelPrivate = useChannelStore((state) => state.isChannelPrivate); const [isThreadOpen, threadMainMessage] = useMessageStore((state) => [ @@ -65,66 +69,9 @@ const ChatBody = ({ height, anonymousMode, showRoles, scrollToBottom, messageLis (state) => state.isUserAuthenticated ); - const username = useUserStore( - (state) => state.username - ); + const username = useUserStore((state) => state.username); - const getMessagesAndRoles = useCallback( - async (anonymousMode) => { - try { - if (!isUserAuthenticated && !anonymousMode) { - return; - } - const { messages } = await RCInstance.getMessages( - anonymousMode, - ECOptions?.enableThreads - ? { - query: { - tmid: { - $exists: false, - }, - }, - } - : undefined, anonymousMode ? false : isChannelPrivate - ); - if (messages) { - setMessages(messages.filter((message) => message._hidden !== true)); - } - if (!isUserAuthenticated) { - // fetch roles only when user is authenticated - return; - } - if (showRoles) { - const { roles } = await RCInstance.getChannelRoles(isChannelPrivate); - // convert roles array from api into object for better search - const rolesObj = roles?.length > 0 - ? roles.reduce((obj, item) => ({ ...obj, [item.u.username]: item }), {}) - : {}; - setRoles(rolesObj); - } - } catch (e) { - console.error(e); - } - }, - [ - isUserAuthenticated, - RCInstance, - ECOptions?.enableThreads, - showRoles, - setMessages, - setRoles, - isChannelPrivate - ] - ); - - const handleGoBack = async () => { - if (isUserAuthenticated) { - getMessagesAndRoles(); - } else { - getMessagesAndRoles(anonymousMode); - } - setFilter(false); - }; + const getMessagesAndRoles = useFetchChatData(showRoles); const getThreadMessages = useCallback(async () => { if (isUserAuthenticated && threadMainMessage?._id) { @@ -147,7 +94,7 @@ const ChatBody = ({ height, anonymousMode, showRoles, scrollToBottom, messageLis RCInstance, threadMainMessage?._id, setThreadMessages, - isChannelPrivate + isChannelPrivate, ]); useEffect(() => { @@ -226,7 +173,6 @@ const ChatBody = ({ height, anonymousMode, showRoles, scrollToBottom, messageLis anonymousMode, ]); - const [scrollPosition, setScrollPosition] = useState(0); const [popupVisible, setPopupVisible] = useState(false); const [isUserScrolledUp, setIsUserScrolledUp] = useState(false); @@ -239,13 +185,12 @@ const ChatBody = ({ height, anonymousMode, showRoles, scrollToBottom, messageLis setPopupVisible(false); }; - const handleScroll = () => { setScrollPosition(messageListRef.current.scrollTop); setIsUserScrolledUp( messageListRef.current.scrollTop + messageListRef.current.clientHeight < - messageListRef.current.scrollHeight + messageListRef.current.scrollHeight ); const isAtBottom = messageListRef.current.scrollTop === 0; @@ -260,7 +205,6 @@ const ChatBody = ({ height, anonymousMode, showRoles, scrollToBottom, messageLis setPopupVisible(true); }; - useEffect(() => { messageListRef.current.addEventListener('scroll', handleScroll); @@ -269,7 +213,6 @@ const ChatBody = ({ height, anonymousMode, showRoles, scrollToBottom, messageLis }; }, [messageListRef]); - useEffect(() => { const isScrolledUp = scrollPosition + messageListRef.current.clientHeight < @@ -300,7 +243,7 @@ const ChatBody = ({ height, anonymousMode, showRoles, scrollToBottom, messageLis threadMessages={threadMessages} /> ) : ( - + )} @@ -314,9 +257,9 @@ const ChatBody = ({ height, anonymousMode, showRoles, scrollToBottom, messageLis /> )}
- {(popupVisible && otherUserMessage) && ( + {popupVisible && otherUserMessage && ( diff --git a/packages/react/src/components/ChatHeader/ChatHeader.js b/packages/react/src/components/ChatHeader/ChatHeader.js index f5b4b53f3..d50cd0dd6 100644 --- a/packages/react/src/components/ChatHeader/ChatHeader.js +++ b/packages/react/src/components/ChatHeader/ChatHeader.js @@ -9,7 +9,7 @@ import { useMemberStore, useSearchMessageStore, useChannelStore, - useToastStore + useToastStore, } from '../../store'; import { DynamicHeader } from '../DynamicHeader'; import { Tooltip } from '../Tooltip'; @@ -20,6 +20,7 @@ import { ActionButton } from '../ActionButton'; import { Menu } from '../Menu'; import useThreadsMessageStore from '../../store/threadsMessageStore'; import { useToastBarDispatch } from '../../hooks/useToastBarDispatch'; +import useFetchChatData from '../../hooks/useFetchChatData'; const ChatHeader = ({ isClosable, @@ -30,6 +31,8 @@ const ChatHeader = ({ channelName, className = '', styles = {}, + anonymousMode, + showRoles, }) => { const { classNames, styleOverrides } = useComponentOverrides('ChatHeader'); const channelInfo = useChannelStore((state) => state.channelInfo); @@ -38,7 +41,9 @@ const ChatHeader = ({ (state) => state.setShowChannelinfo ); const isChannelPrivate = useChannelStore((state) => state.isChannelPrivate); - const setIsChannelPrivate = useChannelStore((state) => state.setIsChannelPrivate); + const setIsChannelPrivate = useChannelStore( + (state) => state.setIsChannelPrivate + ); const { RCInstance } = useRCContext(); @@ -50,6 +55,7 @@ const ChatHeader = ({ ); const dispatchToastMessage = useToastBarDispatch(); + const getMessagesAndRoles = useFetchChatData(showRoles); const avatarUrl = useUserStore((state) => state.avatarUrl); const headerTitle = useMessageStore((state) => state.headerTitle); @@ -64,9 +70,19 @@ const ChatHeader = ({ const toggleShowMembers = useMemberStore((state) => state.toggleShowMembers); const showMembers = useMemberStore((state) => state.showMembers); const setShowSearch = useSearchMessageStore((state) => state.setShowSearch); - const setShowAllThreads = useThreadsMessageStore((state => state.setShowAllThreads)); + const setShowAllThreads = useThreadsMessageStore( + (state) => state.setShowAllThreads + ); const toastPosition = useToastStore((state) => state.position); + const handleGoBack = async () => { + if (isUserAuthenticated) { + getMessagesAndRoles(); + } else { + getMessagesAndRoles(anonymousMode); + } + setFilter(false); + }; const handleLogout = useCallback(async () => { try { @@ -81,23 +97,31 @@ const ChatHeader = ({ const showStarredMessage = useCallback(async () => { const { messages } = await RCInstance.getStarredMessages(); setMessages(messages); - setHeaderTitle("Starred Messages"); + setHeaderTitle('Starred Messages'); setFilter(true); - }, [RCInstance, setMessages, setFilter]); + }, [RCInstance, setMessages, setHeaderTitle, setFilter]); const showPinnedMessage = useCallback(async () => { const { messages } = await RCInstance.getPinnedMessages(); setMessages(messages); - setHeaderTitle("Pinned Messages"); + setHeaderTitle('Pinned Messages'); setFilter(true); - }, [RCInstance, setMessages, setFilter]); + }, [RCInstance, setMessages, setHeaderTitle, setFilter]); const showChannelMembers = useCallback(async () => { - const { members = [] } = await RCInstance.getChannelMembers(isChannelPrivate); + const { members = [] } = await RCInstance.getChannelMembers( + isChannelPrivate + ); setMembersHandler(members); toggleShowMembers(); setShowSearch(false); - }, [RCInstance, setMembersHandler, toggleShowMembers, setShowSearch, isChannelPrivate]); + }, [ + RCInstance, + setMembersHandler, + toggleShowMembers, + setShowSearch, + isChannelPrivate, + ]); const showSearchMessage = useCallback(() => { setShowSearch(true); @@ -121,8 +145,8 @@ const ChatHeader = ({ if (res.success) { setChannelInfo(res.room); if (res.room.t === 'p') setIsChannelPrivate(true); - } else { - if ('errorType' in res && res.errorType === 'error-room-not-found') { + } else if ('errorType' in res) { + if (res.errorType === 'error-room-not-found') { dispatchToastMessage({ type: 'error', message: "Channel doesn't exist. Logging out.", @@ -131,12 +155,18 @@ const ChatHeader = ({ await RCInstance.logout(); } } - }; if (isUserAuthenticated) { getChannelInfo(); } - }, [isUserAuthenticated, RCInstance, setChannelInfo, setIsChannelPrivate]); + }, [ + isUserAuthenticated, + RCInstance, + setChannelInfo, + setIsChannelPrivate, + dispatchToastMessage, + toastPosition, + ]); const menuOptions = useMemo(() => { const options = []; @@ -206,6 +236,7 @@ const ChatHeader = ({ isUserAuthenticated, moreOpts, setFullScreen, + showAllThreads, showChannelMembers, showChannelinformation, showPinnedMessage, @@ -284,23 +315,22 @@ const ChatHeader = ({ avatar )} {fullScreen ? ( - - ) : ( - <> - { - setFullScreen((prev) => !prev); - }} - ghost - display="inline" - square - size='medium' - > - - - + <> + + { + setFullScreen((prev) => !prev); + }} + ghost + display="inline" + square + size="medium" + > + + + )} @@ -312,7 +342,7 @@ const ChatHeader = ({ ghost display="inline" square - size='medium' + size="medium" > @@ -320,11 +350,23 @@ const ChatHeader = ({ {isThreadOpen && ( - + )} {!isThreadOpen && filtered && ( - + )} ); diff --git a/packages/react/src/components/DynamicHeader/DynamicHeader.js b/packages/react/src/components/DynamicHeader/DynamicHeader.js index 7276419ec..8fdb7be1e 100644 --- a/packages/react/src/components/DynamicHeader/DynamicHeader.js +++ b/packages/react/src/components/DynamicHeader/DynamicHeader.js @@ -5,43 +5,42 @@ import { Icon } from '../Icon'; import { Box } from '../Box'; import { ActionButton } from '../ActionButton'; -const DynamicHeader = ({ title, isClosable = false, handleClose = () => { }, iconName }) => { - return ( +const DynamicHeader = ({ + title, + isHeaderIcon = false, + handleClose = () => {}, + iconName, + headerIconName, +}) => ( + - - {isClosable && ( - - - - )} - {!isClosable && ( -
- -
- )} -

{title}

-
+ + + + +

{title}

+ {isHeaderIcon && }
- ); -}; +
+); export default DynamicHeader; DynamicHeader.propTypes = { handleClose: PropTypes.func, title: PropTypes.string, - isClosable: PropTypes.bool, + isHeaderIcon: PropTypes.bool, iconName: PropTypes.string, }; diff --git a/packages/react/src/components/EmbeddedChat.js b/packages/react/src/components/EmbeddedChat.js index bf7dd60d9..3156ed044 100644 --- a/packages/react/src/components/EmbeddedChat.js +++ b/packages/react/src/components/EmbeddedChat.js @@ -21,7 +21,6 @@ import { ToastBarProvider } from './ToastBar'; import { DropBoxOverlay, dropBoxStyles } from './DropBox'; import { styles } from './EmbeddedChat.styles'; - const EmbeddedChat = ({ isClosable = false, setClosableState, @@ -53,7 +52,14 @@ const EmbeddedChat = ({ setShowAvatar(showAvatar); }, [toastBarPosition, showAvatar]); - const { onDrag, data, handleDrag, handleDragEnter, handleDragLeave, handleDragDrop } = useDropBox(); + const { + onDrag, + data, + handleDrag, + handleDragEnter, + handleDragLeave, + handleDragDrop, + } = useDropBox(); if (isClosable && !setClosableState) { throw Error( @@ -127,7 +133,6 @@ const EmbeddedChat = ({ setIsUserAuthenticated(true); }) .catch(console.error); - } else { setIsUserAuthenticated(false); } @@ -187,17 +192,18 @@ const EmbeddedChat = ({ } }; - return ( - {attachmentWindowOpen ? (!!data ? - <> - - - : - + {attachmentWindowOpen ? ( + !!data ? ( + <> + + + ) : ( + + ) ) : null} )} @@ -233,7 +241,7 @@ const EmbeddedChat = ({ diff --git a/packages/react/src/components/MessageList/MessageList.js b/packages/react/src/components/MessageList/MessageList.js index 60cdecd12..9a9203a89 100644 --- a/packages/react/src/components/MessageList/MessageList.js +++ b/packages/react/src/components/MessageList/MessageList.js @@ -15,20 +15,20 @@ import SearchMessage from '../SearchMessage/SearchMessage'; import Roominfo from '../RoomInformation/RoomInformation'; import AllThreads from '../AllThreads/AllThreads'; import { Message } from '../Message'; -import { ActionButton } from '../ActionButton'; -import { Icon } from '../Icon'; + import useThreadsMessageStore from '../../store/threadsMessageStore'; -const MessageList = ({ messages, handleGoBack }) => { +const MessageList = ({ messages }) => { const showSearch = useSearchMessageStore((state) => state.showSearch); const showChannelinfo = useChannelStore((state) => state.showChannelinfo); - const filtered = useMessageStore((state) => state.filtered); const showMembers = useMemberStore((state) => state.showMembers); const members = useMemberStore((state) => state.members); const showReportMessage = useMessageStore((state) => state.showReportMessage); const messageToReport = useMessageStore((state) => state.messageToReport); const showAvatar = useUserStore((state) => state.showAvatar); - const showAllThreads = useThreadsMessageStore((state) => state.showAllThreads); + const showAllThreads = useThreadsMessageStore( + (state) => state.showAllThreads + ); const isMessageNewDay = (current, previous) => !previous || !isSameDay(new Date(current.ts), new Date(previous.ts)); @@ -53,11 +53,7 @@ const MessageList = ({ messages, handleGoBack }) => { ) ); })} - {filtered && ( - - - - )} + {showMembers && } {showReportMessage && } {showSearch && } @@ -71,5 +67,4 @@ export default MessageList; MessageList.propTypes = { messages: PropTypes.arrayOf(PropTypes.shape), - handleGoBack: PropTypes.func, }; diff --git a/packages/react/src/hooks/useFetchChatData.js b/packages/react/src/hooks/useFetchChatData.js new file mode 100644 index 000000000..8f6e6d782 --- /dev/null +++ b/packages/react/src/hooks/useFetchChatData.js @@ -0,0 +1,76 @@ +import { useCallback, useContext } from 'react'; +import RCContext from '../context/RCInstance'; +import { useUserStore, useChannelStore, useMessageStore } from '../store'; + +const useFetchChatData = (showRoles) => { + const { RCInstance, ECOptions } = useContext(RCContext); + const setRoles = useUserStore((state) => state.setRoles); + const isChannelPrivate = useChannelStore((state) => state.isChannelPrivate); + const setMessages = useMessageStore((state) => state.setMessages); + const isUserAuthenticated = useUserStore( + (state) => state.isUserAuthenticated + ); + + const getMessagesAndRoles = useCallback( + async (anonymousMode) => { + try { + if (!isUserAuthenticated && !anonymousMode) { + return; + } + + const { messages } = await RCInstance.getMessages( + anonymousMode, + ECOptions?.enableThreads + ? { + query: { + tmid: { + $exists: false, + }, + }, + } + : undefined, + anonymousMode ? false : isChannelPrivate + ); + + if (messages) { + setMessages(messages.filter((message) => message._hidden !== true)); + } + + if (!isUserAuthenticated) { + // fetch roles only when the user is authenticated + return; + } + + if (showRoles) { + const { roles } = await RCInstance.getChannelRoles(isChannelPrivate); + + // convert roles array from the API into an object for better search + const rolesObj = + roles?.length > 0 + ? roles.reduce( + (obj, item) => ({ ...obj, [item.u.username]: item }), + {} + ) + : {}; + + setRoles(rolesObj); + } + } catch (e) { + console.error(e); + } + }, + [ + isUserAuthenticated, + RCInstance, + ECOptions?.enableThreads, + showRoles, + setMessages, + setRoles, + isChannelPrivate, + ] + ); + + return getMessagesAndRoles; +}; + +export default useFetchChatData; From 30d4852337242a6c735cf90b053a888a5af55986 Mon Sep 17 00:00:00 2001 From: Zishan Ahmad Date: Fri, 16 Feb 2024 22:34:28 +0530 Subject: [PATCH 04/12] fix: UI and Alignment Issues in video recorder modal (#456) * fixed stacking context fixed videorecorder stylings and alignment issues removed unused stylings fixed syntax from fill-rule to fillRule as we are writing JSX * fixed linting and formatted with prettier in changed code --- .../ChatInput/ChatInputFormattingToolbar.js | 20 ++++++----- .../ChatInput/VideoMessageRecoder.js | 14 +++++--- ...le.css => VideoMessageRecorder.module.css} | 20 +---------- .../components/Icon/icons/DisableRecorder.js | 34 +++++++++---------- .../src/components/Icon/icons/VideoRecoder.js | 2 +- 5 files changed, 39 insertions(+), 51 deletions(-) rename packages/react/src/components/ChatInput/{VideoMessage.module.css => VideoMessageRecorder.module.css} (50%) diff --git a/packages/react/src/components/ChatInput/ChatInputFormattingToolbar.js b/packages/react/src/components/ChatInput/ChatInputFormattingToolbar.js index b72911595..f7ccf700f 100644 --- a/packages/react/src/components/ChatInput/ChatInputFormattingToolbar.js +++ b/packages/react/src/components/ChatInput/ChatInputFormattingToolbar.js @@ -10,7 +10,7 @@ import AudioMessageRecorder from './AudioMessageRecorder'; import { Box } from '../Box'; import { Icon } from '../Icon'; import { ActionButton } from '../ActionButton'; -import { Tooltip } from "../Tooltip" +import { Tooltip } from '../Tooltip'; import useComponentOverrides from '../../theme/useComponentOverrides'; import VideoMessageRecorder from './VideoMessageRecoder'; @@ -58,11 +58,11 @@ const ChatInputFormattingToolbar = ({ messageRef, inputRef }) => { input.selectionEnd = input.selectionStart + selectedText.length; }; - const popupStyle= { + const popupStyle = { margin: '0', position: 'absolute', left: '0.375rem', - top:'9.5rem' + top: '9.5rem', }; return ( @@ -70,6 +70,7 @@ const ChatInputFormattingToolbar = ({ messageRef, inputRef }) => { css={css` background-color: #cbced1; display: flex; + position: relative; flex-direction: row; gap: 0.375rem; align-items: center; @@ -110,7 +111,6 @@ const ChatInputFormattingToolbar = ({ messageRef, inputRef }) => { )} {formatter.map((item, index) => ( - { wrapSelection(item.pattern); }} > - - + - ))} - + + + diff --git a/packages/react/src/components/ChatInput/VideoMessageRecoder.js b/packages/react/src/components/ChatInput/VideoMessageRecoder.js index 94489f54d..e079cd7ca 100644 --- a/packages/react/src/components/ChatInput/VideoMessageRecoder.js +++ b/packages/react/src/components/ChatInput/VideoMessageRecoder.js @@ -5,14 +5,14 @@ import React, { useContext, useRef, } from 'react'; -import styles from './VideoMessage.module.css'; +import styles from './VideoMessageRecorder.module.css'; import { useMediaRecorder } from '../../hooks/useMediaRecorder'; import RCContext from '../../context/RCInstance'; import useMessageStore from '../../store/messageStore'; import { Box } from '../Box'; import { Icon } from '../Icon'; import { ActionButton } from '../ActionButton'; -import { Modal } from '../Modal' +import { Modal } from '../Modal'; const VideoMessageRecorder = () => { const videoRef = useRef(null); @@ -38,7 +38,7 @@ const VideoMessageRecorder = () => { const [start, stop] = useMediaRecorder({ constraints: { audio: true, video: true }, // Update constraints as needed onStop, - videoRef: videoRef, + videoRef, }); const stopRecording = async () => { @@ -55,7 +55,6 @@ const VideoMessageRecorder = () => { setRecordState('recording'); try { start(videoRef.current); - console.log(videoRef); // Start recording with the videoRef toogleRecordingMessage(); const startTime = new Date(); setRecordingInterval( @@ -163,7 +162,12 @@ const VideoMessageRecorder = () => {