diff --git a/client/src/components/chat-conversation-list/chat-conversation-list.component.jsx b/client/src/components/chat-conversation-list/chat-conversation-list.component.jsx index a9d48871e..ffc087ae2 100644 --- a/client/src/components/chat-conversation-list/chat-conversation-list.component.jsx +++ b/client/src/components/chat-conversation-list/chat-conversation-list.component.jsx @@ -7,6 +7,8 @@ import { selectSelectedConversation } from "../../redux/messaging/messaging.sele import { TimeAgoFormatter } from "../../utils/DateFormatter"; import PhoneFormatter from "../../utils/PhoneFormatter"; import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; +import { List as VirtualizedList, AutoSizer } from "react-virtualized"; + import "./chat-conversation-list.styles.scss"; const mapStateToProps = createStructuredSelector({ @@ -18,73 +20,87 @@ const mapDispatchToProps = (dispatch) => ({ dispatch(setSelectedConversation(conversationId)), }); -const ChatConversationListComponent = React.forwardRef( - function ChatConversationListComponent( - { - conversationList, - selectedConversation, - setSelectedConversation, - subscribeToMoreConversations, - }, - ref - ) { - useEffect( - () => subscribeToMoreConversations(), - // eslint-disable-next-line react-hooks/exhaustive-deps - [] - ); +function ChatConversationListComponent({ + conversationList, + selectedConversation, + setSelectedConversation, + subscribeToMoreConversations, + loadMoreConversations, +}) { + useEffect( + () => subscribeToMoreConversations(), + // eslint-disable-next-line react-hooks/exhaustive-deps + [] + ); + + const rowRenderer = ({ index, key, style }) => { + const item = conversationList[index]; return ( -
- ( - setSelectedConversation(item.id)} - className={`chat-list-item ${ - item.id === selectedConversation - ? "chat-list-selected-conversation" - : null - }`} - > -
- {item.label &&
{item.label}
} - {item.job_conversations.length > 0 ? ( -
- {item.job_conversations.map((j, idx) => ( -
- -
- ))} -
- ) : ( - {item.phone_num} - )} -
-
-
- {item.job_conversations.length > 0 - ? item.job_conversations.map((j, idx) => ( - - {j.job.ro_number} - - )) - : null} + setSelectedConversation(item.id)} + className={`chat-list-item ${ + item.id === selectedConversation + ? "chat-list-selected-conversation" + : null + }`} + style={style} + > +
+ {item.label &&
{item.label}
} + {item.job_conversations.length > 0 ? ( +
+ {item.job_conversations.map((j, idx) => ( +
+
- {item.updated_at} -
- - + ))} +
+ ) : ( + {item.phone_num} )} - footer={} - /> -
+
+
+
+ {item.job_conversations.length > 0 + ? item.job_conversations.map((j, idx) => ( + + {j.job.ro_number} + + )) + : null} +
+ {item.updated_at} +
+ +
); - } -); + }; -export default connect(mapStateToProps, mapDispatchToProps, null, { - forwardRef: true, -})(ChatConversationListComponent); + return ( +
+ + {({ height, width }) => ( + { + if (scrollTop + clientHeight === scrollHeight) { + loadMoreConversations(); + } + }} + /> + )} + +
+ ); +} + +export default connect( + mapStateToProps, + mapDispatchToProps +)(ChatConversationListComponent); diff --git a/client/src/components/chat-conversation-list/chat-conversation-list.styles.scss b/client/src/components/chat-conversation-list/chat-conversation-list.styles.scss index bfc83d947..20cf8f4ef 100644 --- a/client/src/components/chat-conversation-list/chat-conversation-list.styles.scss +++ b/client/src/components/chat-conversation-list/chat-conversation-list.styles.scss @@ -3,8 +3,9 @@ } .chat-list-container { flex: 1; - overflow: auto; + overflow: hidden; height: 100%; + border: 1px solid gainsboro; } .chat-list-item { @@ -21,4 +22,6 @@ .ro-number-tag { align-self: baseline; } + padding: 12px 24px; + border-bottom: 1px solid gainsboro; } diff --git a/client/src/components/chat-popup/chat-popup.component.jsx b/client/src/components/chat-popup/chat-popup.component.jsx index a3fda4843..5ac4baec1 100644 --- a/client/src/components/chat-popup/chat-popup.component.jsx +++ b/client/src/components/chat-popup/chat-popup.component.jsx @@ -4,9 +4,9 @@ import { ShrinkOutlined, SyncOutlined, } from "@ant-design/icons"; -import { useQuery, useSubscription } from "@apollo/client"; +import { useLazyQuery, useQuery, useSubscription } from "@apollo/client"; import { Badge, Card, Col, Row, Space, Tag, Tooltip, Typography } from "antd"; -import React, { useEffect, useState } from "react"; +import React, { useCallback, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; @@ -25,7 +25,6 @@ import ChatConversationContainer from "../chat-conversation/chat-conversation.co import ChatNewConversation from "../chat-new-conversation/chat-new-conversation.component"; import LoadingSpinner from "../loading-spinner/loading-spinner.component"; import "./chat-popup.styles.scss"; -import { useInView } from "react-intersection-observer"; const mapStateToProps = createStructuredSelector({ selectedConversation: selectSelectedConversation, @@ -42,7 +41,6 @@ export function ChatPopupComponent({ }) { const { t } = useTranslation(); const [pollInterval, setpollInterval] = useState(0); - const { ref, inView } = useInView({}); const { data: unreadData } = useSubscription( UNREAD_CONVERSATION_COUNT_SUBSCRIPTION @@ -56,15 +54,14 @@ export function ChatPopupComponent({ // } // ); - const { loading, data, called, refetch, fetchMore, subscribeToMore } = - useQuery(CONVERSATION_LIST_QUERY, { - variables: { - offset: 0, - }, - fetchPolicy: "cache-and-network", - nextFetchPolicy: "cache-first", - skip: !chatVisible, - }); + const [ + getConversations, + { loading, data, called, fetchMore, subscribeToMore }, + ] = useLazyQuery(CONVERSATION_LIST_QUERY, { + fetchPolicy: "cache-and-network", + nextFetchPolicy: "cache-first", + skip: !chatVisible, + }); const fcmToken = sessionStorage.getItem("fcmtoken"); @@ -77,18 +74,60 @@ export function ChatPopupComponent({ }, [fcmToken]); useEffect(() => { - if (called && chatVisible) refetch(); - }, [chatVisible, called, refetch]); + if (called && chatVisible) + getConversations({ + variables: { + offset: 0, + }, + }); + }, [chatVisible, called, getConversations]); - useEffect(() => { - if (inView && data && data.conversations) { + const loadMoreConversations = useCallback(() => { + if (data) fetchMore({ variables: { offset: data.conversations.length, }, }); - } - }, [inView, data, fetchMore]); + }, [data, fetchMore]); + + const subscribeToMoreConversations = useCallback( + () => + subscribeToMore({ + document: CONVERSATION_LIST_SUBSCRIPTION, + variables: { offset: 0 }, + updateQuery: (prev, { subscriptionData }) => { + console.log("Hello"); + if ( + !subscriptionData.data || + subscriptionData.data.conversations.length === 0 + ) + return prev; + + let conversations = prev.conversations; + const newConversations = subscriptionData.data.conversations; + + for (const conversation of newConversations) { + const index = conversations.findIndex( + (prevConversation) => prevConversation.id === conversation.id + ); + + if (index !== -1) { + conversations.splice(index, 1); + conversations.unshift(conversation); + continue; + } + + conversation.unshift(conversation); + } + + return Object.assign({}, prev, { + conversations: conversations, + }); + }, + }), + [subscribeToMore] + ); const unreadCount = unreadData?.messages_aggregate.aggregate.count || 0; @@ -105,10 +144,10 @@ export function ChatPopupComponent({ - refetch()} - /> + /> */} {pollInterval > 0 && ( {t("messaging.labels.nopush")} )} @@ -125,7 +164,8 @@ export function ChatPopupComponent({ ) : ( { + loadMoreConversations={loadMoreConversations} + subscribeToMoreConversations={() => subscribeToMore({ document: CONVERSATION_LIST_SUBSCRIPTION, variables: { offset: 0 }, @@ -135,16 +175,33 @@ export function ChatPopupComponent({ subscriptionData.data.conversations.length === 0 ) return prev; + + let conversations = [...prev.conversations]; const newConversations = subscriptionData.data.conversations; + for (const conversation of newConversations) { + const index = conversations.findIndex( + (prevConversation) => + prevConversation.id === conversation.id + ); + + if (index !== -1) { + conversations.splice(index, 1); + conversations.unshift(conversation); + + continue; + } + + conversations.unshift(conversation); + } + return Object.assign({}, prev, { - conversations: [...newConversations], + conversations: conversations, }); }, - }); - }} - ref={ref} + }) + } /> )}