diff --git a/app/assets/stylesheets/chat.scss b/app/assets/stylesheets/chat.scss
index ed45919c0..c969534ec 100644
--- a/app/assets/stylesheets/chat.scss
+++ b/app/assets/stylesheets/chat.scss
@@ -1204,3 +1204,25 @@
width:96%;
}
}
+
+.jumpback{
+ position: relative;
+}
+
+.jumpback__messages{
+ position: absolute;
+ bottom: 10px;
+ right: 20px;
+ background: var(--theme-background, #f5f6f7);
+ border: 2px solid #111;
+ padding: 10px;
+ border-radius: 20px;
+ cursor: pointer;
+ font-size: 14px;
+ text-transform: uppercase;
+ font-weight: bold;
+}
+
+.jumpback__hide{
+ display: none;
+}
\ No newline at end of file
diff --git a/app/controllers/chat_channels_controller.rb b/app/controllers/chat_channels_controller.rb
index 28aa55489..34bd33596 100644
--- a/app/controllers/chat_channels_controller.rb
+++ b/app/controllers/chat_channels_controller.rb
@@ -17,7 +17,7 @@ class ChatChannelsController < ApplicationController
end
def show
- @chat_messages = @chat_channel.messages.includes(:user).order("created_at DESC").limit(50)
+ @chat_messages = @chat_channel.messages.includes(:user).order("created_at DESC").offset(params[:message_offset]).limit(150)
end
def create
diff --git a/app/javascript/chat/__tests__/__snapshots__/chat.test.jsx.snap b/app/javascript/chat/__tests__/__snapshots__/chat.test.jsx.snap
index 1935ce80f..be5723c27 100644
--- a/app/javascript/chat/__tests__/__snapshots__/chat.test.jsx.snap
+++ b/app/javascript/chat/__tests__/__snapshots__/chat.test.jsx.snap
@@ -176,12 +176,28 @@ exports[` should load chat 1`] = `
diff --git a/app/javascript/chat/actions.js b/app/javascript/chat/actions.js
index 53f54b424..7e516d8ff 100644
--- a/app/javascript/chat/actions.js
+++ b/app/javascript/chat/actions.js
@@ -1,5 +1,5 @@
-export function getAllMessages(channelId, successCb, failureCb) {
- fetch(`/chat_channels/${channelId}`, {
+export function getAllMessages(channelId, messageOffset, successCb, failureCb) {
+ fetch(`/chat_channels/${channelId}?message_offset=${messageOffset}`, {
Accept: 'application/json',
'Content-Type': 'application/json',
credentials: 'same-origin',
diff --git a/app/javascript/chat/chat.jsx b/app/javascript/chat/chat.jsx
index ac62d423e..ea3bb2bd4 100644
--- a/app/javascript/chat/chat.jsx
+++ b/app/javascript/chat/chat.jsx
@@ -60,6 +60,9 @@ export default class Chat extends Component {
inviteChannels: [],
soundOn: true,
videoOn: true,
+ messageOffset: 0,
+ allMessagesLoaded: false,
+ currentMessageLocation: 0,
};
}
@@ -72,6 +75,7 @@ export default class Chat extends Component {
isMobileDevice,
channelPaginationNum,
} = this.state;
+
this.setupChannels(chatChannels);
const channelsForPusherSub = chatChannels.filter(
this.channelTypeFilter('open'),
@@ -113,12 +117,18 @@ export default class Chat extends Component {
}
componentDidUpdate() {
- const { scrolled } = this.state;
- if (document.getElementById('messagelist')) {
+ const { scrolled, currentMessageLocation } = this.state;
+ const messageList = document.getElementById('messagelist');
+ if (messageList) {
if (!scrolled) {
scrollToBottom();
}
}
+
+ if (currentMessageLocation && messageList.scrollTop === 0) {
+ messageList.scrollTop =
+ messageList.scrollHeight - (currentMessageLocation + 30);
+ }
}
liveCoding = e => {
@@ -257,13 +267,13 @@ export default class Chat extends Component {
};
setupChannel = channelId => {
- const { messages } = this.state;
+ const { messages, messageOffset } = this.state;
if (
!messages[channelId] ||
messages[channelId].length === 0 ||
messages[channelId][0].reception_method === 'pushed'
) {
- getAllMessages(channelId, this.receiveAllMessages);
+ getAllMessages(channelId, messageOffset, this.receiveAllMessages);
}
this.subscribePusher(`presence-channel-${channelId}`);
};
@@ -853,17 +863,91 @@ export default class Chat extends Component {
return '';
};
+ handleMessageScroll = () => {
+ const {
+ allMessagesLoaded,
+ messages,
+ activeChannelId,
+ messageOffset,
+ } = this.state;
+
+ const jumpbackButton = document.getElementById('jumpback_button');
+
+ if (this.scroller) {
+ const scrolledRatio =
+ (this.scroller.scrollTop + this.scroller.clientHeight) /
+ this.scroller.scrollHeight;
+
+ if (scrolledRatio < 0.7) {
+ jumpbackButton.classList.remove('jumpback__hide');
+ } else if (scrolledRatio > 0.8) {
+ jumpbackButton.classList.add('jumpback__hide');
+ }
+
+ if (this.scroller.scrollTop === 0 && !allMessagesLoaded) {
+ getAllMessages(
+ activeChannelId,
+ messageOffset + messages[activeChannelId].length,
+ this.addMoreMessages,
+ );
+ const curretPosition = this.scroller.scrollHeight;
+ this.setState({ currentMessageLocation: curretPosition });
+ }
+ }
+ };
+
+ addMoreMessages = res => {
+ const { chatChannelId, messages } = res;
+
+ if (messages.length > 0) {
+ this.setState(prevState => ({
+ messages: {
+ [chatChannelId]: [...messages, ...prevState.messages[chatChannelId]],
+ },
+ }));
+ } else {
+ this.setState({ allMessagesLoaded: true });
+ }
+ };
+
+ jumpBacktoBottom = () => {
+ scrollToBottom();
+ document
+ .getElementById('jumpback_button')
+ .classList.remove('jumpback__hide');
+ };
+
renderActiveChatChannel = (channelHeader, incomingCall) => {
const { state, props } = this;
return (
{channelHeader}
-
+
{
+ this.scroller = scroller;
+ }}
+ id="messagelist"
+ >
{this.renderMessages()}
{incomingCall}
+