Skip to content

Commit 6ab3679

Browse files
committed
Export logic to custom hook, add scrolling functionalities
Scrolling functionalities: * When conversation show-up, automatically scroll messages to bottom * When new message create or received scroll to bottom * When scroll to top get messages history (it's not finished, waiting for backend)
1 parent 4893856 commit 6ab3679

File tree

3 files changed

+131
-34
lines changed

3 files changed

+131
-34
lines changed

src/components/Messages/Messages.js

Lines changed: 57 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,70 @@
1-
import React, { useEffect, useRef } from "react";
2-
import { useParams } from "react-router-dom";
1+
import React from "react";
2+
import { useTransition, animated } from "react-spring";
33

44
// Components
55
import Message from "./Message/Message";
66

77
// Styles
88
import classes from "./Messages.module.scss";
99

10-
function Messages({ messages, members }) {
11-
const { conversationId } = useParams();
12-
const refMessagesEnd = useRef();
13-
// const isIntersecting = useOnScreen(refMessagesEnd);
10+
// Hooks
11+
import useMessages from "./useMessages";
1412

15-
useEffect(() => {
16-
refMessagesEnd.current.scrollIntoView();
17-
}, [conversationId]);
13+
function Messages({ messages, members }) {
14+
const { showMessages, refMessagesStart, refMessagesEnd } = useMessages(
15+
messages
16+
);
17+
const transitions = useTransition(showMessages, null, {
18+
from: {
19+
width: "100%",
20+
display: "grid",
21+
gridTemplateColumns: "1rem 2fr 5fr 2fr 1rem",
22+
alignContent: "start",
23+
listStyle: "none",
24+
paddingTop: "1rem",
25+
position: "relative",
26+
opacity: 0,
27+
},
28+
enter: { opacity: 1 },
29+
leave: { opacity: 0 },
30+
});
1831

1932
return (
20-
<ul className={classes.Messages}>
21-
{messages.length !== 0
22-
? messages.map((message) => {
23-
return (
24-
<Message
25-
content={message.content}
26-
senderId={message.sender}
27-
avatar={
28-
members.find(
29-
(member) =>
30-
member?._id === message.sender ||
31-
member.id === message.sender
32-
).avatar50x50
33-
}
34-
key={message.tempId ? message.tempId : message._id}
35-
isSending={message.isSending}
36-
/>
37-
);
38-
})
39-
: null}
40-
<li ref={refMessagesEnd}>&nbsp;</li>
41-
</ul>
33+
<div className={classes.MessagesWrapper}>
34+
{transitions.map(
35+
({ item, props, key }) =>
36+
item && (
37+
<animated.ul key={key} style={props}>
38+
<li
39+
ref={refMessagesStart}
40+
className={classes.MessagesStartListItem}
41+
>
42+
&nbsp;
43+
</li>
44+
{messages.map((message) => {
45+
return (
46+
<Message
47+
content={message.content}
48+
senderId={message.sender}
49+
avatar={
50+
members.find(
51+
(member) =>
52+
member?._id === message.sender ||
53+
member.id === message.sender
54+
).avatar50x50
55+
}
56+
key={message.tempId ? message.tempId : message._id}
57+
isSending={message.isSending}
58+
/>
59+
);
60+
})}
61+
<li ref={refMessagesEnd} className={classes.MessagesEndListItem}>
62+
&nbsp;
63+
</li>
64+
</animated.ul>
65+
)
66+
)}
67+
</div>
4268
);
4369
}
4470

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,35 @@
11
@import "../../styles/scrollbar";
22

3-
.Messages {
4-
display: grid;
3+
.MessagesWrapper {
54
grid-row: 2 / 3;
65
height: 0;
76
min-height: 100%;
87
overflow-y: auto;
8+
@include withCustomScrollbar;
9+
}
10+
11+
.Messages {
12+
display: grid;
913
grid-template-columns: 1rem 2fr 5fr 2fr 1rem;
1014
align-content: start;
1115
list-style: none;
1216
padding-top: 1rem;
17+
position: relative;
18+
}
1319

14-
@include withCustomScrollbar;
20+
.MessagesEndListItem {
21+
position: absolute;
22+
bottom: 0;
23+
left: 0;
24+
width: 100%;
25+
height: 15vh;
26+
}
27+
28+
.MessagesStartListItem {
29+
position: absolute;
30+
top: 0;
31+
left: 0;
32+
width: 100%;
33+
margin-top: 80px;
34+
height: 15vh;
1535
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { useEffect, useState, useRef } from "react";
2+
import { useSelector } from "react-redux";
3+
import useOnScreen from "../../hooks/useOnScreen";
4+
5+
const useMessages = (messages) => {
6+
const refMessagesEnd = useRef(null);
7+
const refMessagesStart = useRef(null);
8+
const isLoaded = useSelector((state) => state.main.isLoaded);
9+
const [isInitial, setIsInitial] = useState(true);
10+
const isMessagesEndVisible = useOnScreen(refMessagesEnd);
11+
const isMessagesStartVisible = useOnScreen(refMessagesStart);
12+
13+
useEffect(() => {
14+
if (isLoaded && messages.length !== 0) {
15+
// Initially show messages in the end, without smooth scroll
16+
if (isInitial) {
17+
refMessagesEnd.current.scrollIntoView(false);
18+
setIsInitial(false);
19+
}
20+
// Scroll smooth when user is in the end of messages
21+
else if (isMessagesEndVisible) {
22+
refMessagesEnd.current.scrollIntoView({ behavior: "smooth" });
23+
}
24+
// Scroll to last messages when logged user send message
25+
else if (
26+
Object.prototype.hasOwnProperty.call(
27+
messages[messages.length - 1],
28+
"tempId"
29+
)
30+
) {
31+
refMessagesEnd.current.scrollIntoView({ behavior: "smooth" });
32+
}
33+
}
34+
}, [messages, isLoaded, isMessagesEndVisible, isInitial, refMessagesEnd]);
35+
36+
useEffect(() => {
37+
if (isMessagesStartVisible) {
38+
console.log("download");
39+
// TO-DO
40+
// GET HISTORY
41+
}
42+
}, [isMessagesStartVisible]);
43+
44+
return {
45+
showMessages: messages.length !== 0,
46+
refMessagesStart,
47+
refMessagesEnd,
48+
};
49+
};
50+
51+
export default useMessages;

0 commit comments

Comments
 (0)