chat-ui-kit-react icon indicating copy to clipboard operation
chat-ui-kit-react copied to clipboard

Question: is there a way to open chat on first unread message? (Jump to message)

Open yevhen-logosha opened this issue 3 years ago • 6 comments

First of all awesome work! 🎉

Have a question, consider this scenario:

  • opening chat window
  • fetching for messages from api
  • getting say 20 old read messages and 40 new unread
  • is there a way to open chat window in a way that last read and first unread are sort of in the middle of the screen ?

Thank you.

yevhen-logosha avatar Apr 05 '21 11:04 yevhen-logosha

Hi @yevhen-logosha, thank you for your question. I'm glad you appreciate this library :)

Currently scrolling to a specific point is not supported.

However, I wonder how to achieve this. I think an option might be to render a custom message that indicates that this is the first unread message. For example, this could be a hidden div with the data-first-unread-message attribute. You can also add data-* attribute to a <Message /> or <MessageGroup /> component it will be added to main component div.

Maybe the <Message /> component should have the unread attribute, or perhaps this attribute should be added to the <MessageSeparator /> component. In chat interfaces such a separator is often placed in front of unread messages.

The next step should be to get a reference to this element and scroll the message window to it with element.scrollTo(), element.scrollTop() or element.scrollIntoView().

I will try to implement this feature. However, as long as it's not natively supported, you can try a small workaround by implementing the described technique by yourself. You can access the message list scroll window by "[data-cs-message-list]" css selector.

supersnager avatar Apr 06 '21 09:04 supersnager

https://github.com/dizco/react-scrollable-feed Can this help

no-1ne avatar Apr 08 '21 23:04 no-1ne

@startupgurukul One can try a third-party library to handle scrolling. But, keep in mind that the <MessageInput /> has the vertical auto-resize feature that affects vertical size of the <MessageList />. So it can be hard to deal with it using another scrollable window. However, please let me know if you have had any positive experiences of using a different scrolling component.

supersnager avatar Apr 09 '21 06:04 supersnager

@supersnager thanks for reply! I was thinking something along your suggestion too, using <MessageList.Content /> rendered conditionally if there is unread count, yet keep getting ref warning Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

thus unable to obtain ref of <MessageList.Content />

Tried using <Message /> too, same warning and ref.current is null 🤔

const Chat = () => {

....

  useEffect(() => {
    unreadCountRef?.current?.scrollIntoView({
      behavior: 'smooth',
      block: 'start',
    });
  }, []);

  const getMessageHistory = () => {
    return messages.map((message) => {
      const hasLastUnread = chatMessagesByTopic.getChatMessageByTopic.lastViewedMessageId === message.id;
      const messageDirection = message.ownMessage ? 'outgoing' : 'incoming';
      const messageFooterMessage = moment(message.createdAt).format('MMM DD, YYYY [at] h:mma z');
      return (
        <>
          {unreadCount && hasLastUnread && (
            <MessageList.Content ref={unreadCountRef}>{unreadCount} Unread Messages</MessageList.Content>
          )}
          <StyledMessage
            $isOwnMessage={message.ownMessage}
            key={message.id}
            model={{
              message: message.messageBody,
              direction: messageDirection,
            }}
          >
            <StyledMessage.Footer sender={messageFooterMessage} />
          </StyledMessage>
        </>
      );
    });
  };

  return (
    <div style={{ position: 'relative', height: '500px' }}>
      <StyledMainContainer>
        <StyledChatContainer>
          <MessageList loadingMore={loadingMore} onYReachStart={onYReachStart}>
            {!chatMessagesByTopic ? <ServiceMessage>No Messages Yet</ServiceMessage> : getMessageHistory()}
          </MessageList>
          {chatMessagesByTopic && (
            <StyledMessageInputGroupContainer as={MessageInput}>
              <MessageInput
                ref={inputRef}
                onChange={(msg) => setMsgInputValue(msg)}
                value={msgInputValue}
                sendButton={false}
                attachButton={false}
                onSend={handleSend}
                autoFocus
                style={{
                  flexGrow: 1,
                  borderTop: 0,
                }}
              />
              <StyledButton isTall onClick={() => handleSend(msgInputValue)} disabled={msgInputValue.length === 0}>
                Send
              </StyledButton>
            </StyledMessageInputGroupContainer>
          )}
        </StyledChatContainer>
      </StyledMainContainer>
    </div>
  );
}

using styled-components if it matters.. but not for MessageList.Content

yevhen-logosha avatar Apr 10 '21 13:04 yevhen-logosha

hm.. getting element via JS instead of useRef did the job.

yevhen-logosha avatar Apr 10 '21 15:04 yevhen-logosha

@yevhen-logosha Most components in the library are functional components, which don't have refs. You can use plain JS (as you did) or wrap a component into your own with ref.

supersnager avatar Apr 12 '21 18:04 supersnager