Search code examples
reactjsiframesubscriptionrocket.chatread-unread

Тhe number of unread messages is not reset after reading, Rocket Chat Iframe integration in react typescript project


No matter which request I use for getting room's unread messages count, it works unpredictably, some times it show the unread count correctly some times not.

           {
                url:`/api/v1/channels.counters?roomId=${roomId}`,  
                headers: {
                    'X-Auth-Token': token,
                    'X-User-Id': userId
                }
            }

            {
                url:`/api/v1/subscriptions.get?updatedSince=2017-11-25T15:08:17.248Z`,  
                headers: {
                    'X-Auth-Token': token,
                    'X-User-Id': userId
                }
            }

I did the integration via iframe which looks like this

import { useGetRocketChatTokenMutation } from 'api/clientApi';
import Cookies from 'js-cookie';
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { parseJwt } from 'utils/parseJwt';
import styles from './Support.styles.scss';

const rocketChatHost = 'https://example.com';


export function Support() {
  const {t, i18n} = useTranslation('translation')
  const jwt = Cookies.get('token');
  const { sub } = parseJwt(jwt);
  const [ savedData, setSavedData ] = useState<SavedRcData>()
  const [getRchatToken] = useGetRocketChatTokenMutation();
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    getRchatToken({login: sub, password: '', languageId: i18n.language})
    .then((res: any) => {
      if (res.data) {    
        console.log("data: ", res.data)
        Cookies.set('rc-data', JSON.stringify(res.data))
        setSavedData(res.data)
      }
    })
    .catch((err) => {
      console.log(err, 'error')
    })
    .finally(() => {
      setIsLoading(false)
    })
  }, []);

  useEffect(()=>{
    async function fetchAndInject() {
      if (savedData !== undefined && savedData !== null ) {
        injectRocketChatIframe(savedData.token, savedData.channelName);
      }
    }
  
    fetchAndInject();
  },[savedData])


  function injectRocketChatIframe(token:string, channel:string) {
    const iframe = document.createElement('iframe');
    iframe.id = 'rocketChatFrame';

    iframe.src = `${rocketChatHost}/channel/${channel}?layout=embedded`;

    document.getElementById('rocket-chat-target').appendChild(iframe);

    iframe.addEventListener('load', () => {
      iframe.contentWindow.postMessage({
        event: 'login-with-token',
        loginToken: token,
      }, `${rocketChatHost}`);
    });
  }
  


  return (
    <div>
      { isLoading ?
      <span>{t('loading...')}</span>
      :
        savedData == undefined || savedData == null ?
        <div>
          <div>
            <span>{t('contact us:')} <a href="mailto:[email protected]">[email protected]</a></span>            
          </div>
        </div>
        :
        null        
      }
      <div style={savedData == undefined || savedData == null ? {display: "none"} : {display: "flex"}} id="rocket-chat-target" />
    </div>
  );
}

interface SavedRcData {
  token: string,
  channelName: string
}

I tried to directly fetch unread count from channel's details endpoint by providing roomId it is showing the right unread count but not every time resets it after reading, in 2 cases out of 5.

Then I found another endpoint 'subscriptions' where you apply the same logic (provide roomId get channel details), unfortunately nothing change, I assume that unread count gets processed by the same function in the source code.


Solution

  • The reason why you're facing the error is due to the empty dependency array for the useEffect wrapping the api call for  rChatTokenData.

    the empty dependency array will cause the rChatTokenData to be fetched only once on page load, therefore savedData will be set once. Therefore, the other useEffect where its dependency array contains savedData will only be called triggered once, which means that injectRocketChatIframe(i assume this function will update the number of unread messages) will only be called once and will not be updated afterwards unless you refresh the page.

    Also, it is not a good idea to wrap your API calls within a useEffect as it might lead to unexpected side effects.

    Try using useQuery instead - https://tanstack.com/query/v4/docs/framework/react/reference/useQuery.

    import { useQuery } from 'react-query';
    const {t, i18n} = useTranslation('translation');
    const { sub } = parseJwt(jwt);
    const { data: rChatTokenData, isLoading } = useQuery(
        [i18n, sub],
        () => getRchatToken({login: sub, password: '', languageId: i18n.language})
    )
    

    The data from the api call will be in rChatTokenData, and you can check if the API call is complete using from isLoading.