Skip to content

Commit

Permalink
Fix: scrolling of the messages container in the Consultation page
Browse files Browse the repository at this point in the history
  • Loading branch information
georgipavlov-7DIGIT committed Jul 28, 2023
1 parent 1299281 commit 4a4813b
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 45 deletions.
2 changes: 2 additions & 0 deletions src/blocks/VideoRoom/VideoRoom.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export function VideoRoom({
leaveConsultation,
handleSendMessage,
hasUnreadMessages,
isClientInSession,
token,
t,
}) {
Expand Down Expand Up @@ -66,6 +67,7 @@ export function VideoRoom({
isMicrophoneOn={isMicrophoneOn}
isRoomConnecting={!localParticipant}
hasUnreadMessages={hasUnreadMessages}
isInSession={isClientInSession}
t={t}
/>

Expand Down
189 changes: 149 additions & 40 deletions src/pages/Consultation/Consultation.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React, {
useRef,
useCallback,
useContext,
useMemo,
} from "react";
import { useTranslation } from "react-i18next";
import { Navigate, useLocation, useNavigate } from "react-router-dom";
Expand All @@ -21,9 +22,11 @@ import {
Toggle,
TypingIndicator,
} from "@USupport-components-library/src";

import {
useWindowDimensions,
ONE_HOUR,
getDateView,
} from "@USupport-components-library/utils";

import {
Expand All @@ -33,7 +36,9 @@ import {
useDebounce,
useGetAllChatHistoryData,
} from "#hooks";

import { Page, VideoRoom } from "#blocks";

import { RootContext } from "#routes";

import { Logger } from "twilio-video";
Expand All @@ -44,6 +49,21 @@ import "./consultation.scss";

const SOCKET_IO_URL = `${import.meta.env.VITE_SOCKET_IO_URL}`;

const systemMessageTypes = [
"client_joined",
"client_left",
"client_microphone_on",
"client_microphone_off",
"client_camera_on",
"client_camera_off",
"provider_joined",
"provider_left",
"provider_microphone_on",
"provider_microphone_off",
"provider_camera_on",
"provider_camera_off",
];

/**
* Consultation
*
Expand Down Expand Up @@ -84,15 +104,31 @@ export const Consultation = () => {
const [showOptions, setShowOptions] = useState(false);
const [search, setSearch] = useState("");
const [hasUnreadMessages, setHasUnreadMessages] = useState(true);
const [isClientInSession, setIsClientInSession] = useState(false);
const [isClientTyping, setIsClientTyping] = useState(false);
const [isChatShownOnTablet, setIsChatShownOnTablet] = useState(true);

const debouncedSearch = useDebounce(search, 500);

const checkHasClientJoined = (messages) => {
// Sort the messages by time descending so the latest messages are first
// Then check which one of the following two cases is true:
const joinMessages = messages
.filter(
(x) => x.content === "client_joined" || x.content === "client_left"
)
.sort((a, b) => new Date(Number(b.time)) - new Date(Number(a.time)));
return joinMessages[0].content === "client_joined";
};

const chatDataQuery = useGetChatData(consultation?.chatId, (data) => {
setMessages((prev) => ({
...prev,
currentSession: data.messages,
}));
{
setIsClientInSession(checkHasClientJoined(data.messages));
setMessages((prev) => ({
...prev,
currentSession: data.messages,
}));
}
});

const clientId = chatDataQuery.data?.clientDetailId;
Expand All @@ -103,6 +139,16 @@ export const Consultation = () => {
true
);

const [areMessagesHidden, setAreMessagesHidden] = useState(true);

const hasMessages = useMemo(() => {
return (
messages?.currentSession?.length > 0 ||
messages?.previousSessions?.length > 0
);
}, [messages]);

// End of session alerts
useEffect(() => {
const endTime = new Date(consultation.timestamp + ONE_HOUR);
let isTenMinAlertShown,
Expand Down Expand Up @@ -134,6 +180,7 @@ export const Consultation = () => {
};
}, []);

// Calculate all chat history
useEffect(() => {
if (
allChatHistoryQuery.data?.messages &&
Expand Down Expand Up @@ -203,13 +250,38 @@ export const Consultation = () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useEffect(() => {
let timeout, timeoutTwo;
if (hasMessages && areMessagesHidden && isChatShownOnMobile) {
timeout = setTimeout(() => {
if (backdropMessagesContainerRef.current) {
backdropMessagesContainerRef.current.scrollTop =
backdropMessagesContainerRef.current.scrollHeight;
}
setAreMessagesHidden(false);
}, 1000);
}

if (!areMessagesHidden && !isChatShownOnMobile) {
timeoutTwo = setTimeout(() => {
setAreMessagesHidden(true);
}, 300);
}

return () => {
if (timeout) clearTimeout(timeout);
if (timeoutTwo) clearTimeout(timeoutTwo);
};
}, [messages, isChatShownOnMobile]);

// Scroll the messages container to the bottom when a new message is received
useEffect(() => {
if (
(messages.currentSession?.length > 0 ||
messages.previousSessions?.length > 0) &&
backdropMessagesContainerRef.current &&
backdropMessagesContainerRef.current.scrollHeight > 0
backdropMessagesContainerRef.current.scrollHeight > 0 &&
!areMessagesHidden
) {
backdropMessagesContainerRef.current.scrollTo({
top: backdropMessagesContainerRef.current?.scrollHeight,
Expand All @@ -220,6 +292,7 @@ export const Consultation = () => {
messages,
backdropMessagesContainerRef.current?.scrollHeight,
debouncedSearch,
areMessagesHidden,
]);

const onSendSuccess = (newMessage) => {
Expand All @@ -237,6 +310,11 @@ export const Consultation = () => {
const leaveConsultationMutation = useLeaveConsultation();

const receiveMessage = (message) => {
if (message.content === "client_left") {
setIsClientInSession(false);
} else if (message.content === "client_joined") {
setIsClientInSession(true);
}
setHasUnreadMessages(true);
setMessages((messages) => {
return {
Expand All @@ -246,21 +324,6 @@ export const Consultation = () => {
});
};

const systemMessageTypes = [
"client_joined",
"client_left",
"client_microphone_on",
"client_microphone_off",
"client_camera_on",
"client_camera_off",
"provider_joined",
"provider_left",
"provider_microphone_on",
"provider_microphone_off",
"provider_camera_on",
"provider_camera_off",
];

const renderAllMessages = useCallback(() => {
if (chatDataQuery.isLoading) return <Loading size="lg" />;

Expand All @@ -273,8 +336,15 @@ export const Consultation = () => {
message.content?.toLowerCase().includes(debouncedSearch.toLowerCase())
);
}
let lastDate;
const messagesToReturn = messagesToShow.map((message, index) => {
let shouldShowDate = false;
const currentMessageDate = getDateView(new Date(Number(message.time)));
if (currentMessageDate !== lastDate) {
shouldShowDate = true;
lastDate = currentMessageDate;
}

const messagesToReturn = messagesToShow?.map((message, index) => {
if (message.type === "system") {
if (!areSystemMessagesShown) return null;
return (
Expand All @@ -286,6 +356,7 @@ export const Consultation = () => {
: message.content
}
date={new Date(Number(message.time))}
showDate={shouldShowDate}
/>
);
} else {
Expand All @@ -296,6 +367,7 @@ export const Consultation = () => {
message={message.content}
sent
date={new Date(Number(message.time))}
showDate={shouldShowDate}
/>
);
} else {
Expand All @@ -305,6 +377,7 @@ export const Consultation = () => {
message={message.content}
received
date={new Date(Number(message.time))}
showDate={shouldShowDate}
/>
);
}
Expand Down Expand Up @@ -349,7 +422,6 @@ export const Consultation = () => {
});
};

const [isChatShownOnTablet, setIsChatShownOnTablet] = useState(true);
const toggleChat = () => {
if (!isChatShownOnMobile) {
setTimeout(() => {
Expand Down Expand Up @@ -436,10 +508,11 @@ export const Consultation = () => {
leaveConsultation={leaveConsultation}
handleSendMessage={handleSendMessage}
hasUnreadMessages={hasUnreadMessages}
isClientInSession={isClientInSession}
token={token}
t={t}
/>
{isChatShownOnTablet && (
{isChatShownOnTablet && width >= 1366 && (
<MessageList
messages={messages}
handleSendMessage={handleSendMessage}
Expand All @@ -461,9 +534,9 @@ export const Consultation = () => {
</div>
<Backdrop
classes="page__consultation__chat-backdrop"
isOpen={isChatShownOnMobile}
isOpen={isChatShownOnMobile && width < 1024}
onClose={() => setIsChatShownOnMobile(false)}
reference={width < 768 ? backdropMessagesContainerRef : null}
// reference={width < 768 ? backdropMessagesContainerRef : null}
headingComponent={
<OptionsContainer
showOptions={showOptions}
Expand All @@ -479,21 +552,19 @@ export const Consultation = () => {
}
>
<div className="page__consultation__chat-backdrop__container">
{areMessagesHidden && <Loading size="lg" />}
<div
ref={width >= 768 ? backdropMessagesContainerRef : null}
ref={backdropMessagesContainerRef}
className={`page__consultation__container__messages__messages-container ${
showOptions
? "page__consultation__container__messages__messages-container--show-options"
: ""
}`}
style={{
visibility: areMessagesHidden ? "hidden" : "visible",
}}
>
{renderAllMessages()}
<div
style={{
width: "100%",
marginBottom: width >= 768 ? "100px" : "50px",
}}
/>
</div>
{(isChatShownOnMobile || width >= 768) && (
<SendMessage
Expand Down Expand Up @@ -539,20 +610,52 @@ const MessageList = ({
};
}, []);

const belowMessagesRef = useRef(null);
const [isHidden, setIsHidden] = useState(true);

useEffect(() => {
let timeout;
if (
messages?.currentSession?.length > 0 ||
messages?.previousSessions?.length > 0
) {
timeout = setTimeout(() => {
if (messagesContainerRef.current) {
messagesContainerRef.current.scrollTop =
messagesContainerRef.current.scrollHeight;
}
setIsHidden(false);
}, 1000);
}

return () => clearTimeout(timeout);
}, [messages]);

useEffect(() => {
let timeout;
if (
(messages.currentSession?.length > 0 ||
messages.previousSessions?.length > 0) &&
messagesContainerRef.current &&
messagesContainerRef.current.scrollHeight > 0 &&
showMessages
messagesContainerRef.current?.scrollHeight > 0 &&
showMessages &&
!isHidden
) {
messagesContainerRef.current.scrollTo({
top: messagesContainerRef.current?.scrollHeight,
behavior: "smooth",
});
timeout = setTimeout(() => {
messagesContainerRef.current.scrollTo({
top: messagesContainerRef.current?.scrollHeight,
behavior: "smooth",
});
}, 300);
}
}, [messages, messagesContainerRef.current?.scrollHeight, showMessages]);
return () => {
if (timeout) clearTimeout(timeout);
};
}, [
messages,
messagesContainerRef.current?.scrollHeight,
showMessages,
isHidden,
]);

return width >= 1024 ? (
<div style={{ position: "relative" }}>
Expand All @@ -568,16 +671,22 @@ const MessageList = ({
isAbsolute
t={t}
/>
{isHidden && <Loading />}

<div
ref={messagesContainerRef}
className={`page__consultation__container__messages__messages-container ${
showOptions
? "page__consultation__container__messages__messages-container--show-options"
: ""
}`}
style={{
visibility: isHidden ? "hidden" : "visible",
}}
>
{showMessages && renderAllMessages()}
</div>
<div ref={belowMessagesRef} />
<SendMessage
handleSubmit={handleSendMessage}
onTextareaFocus={onTextareaFocus}
Expand Down
Loading

0 comments on commit 4a4813b

Please sign in to comment.