Feature🚀: Ability to see chat history by scrolling up (#4903)
* Feature🚀: Ability to see chat history by scrolling up * Test samples updated * Feature Enhancement 🛠 : Jump back to recent messages If you scroll far away just click this button to go back  * Test case added * Bug Fix 🐞: Scrolling problem with large screen and re-rendering issue
This commit is contained in:
parent
d9803fef13
commit
147b0936df
5 changed files with 130 additions and 8 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -176,12 +176,28 @@ exports[`<Chat /> should load chat 1`] = `
|
|||
<div
|
||||
class="activechatchannel__messages"
|
||||
id="messagelist"
|
||||
onScroll={[Function]}
|
||||
ref={[Function]}
|
||||
>
|
||||
<div
|
||||
class="messagelist__sentinel"
|
||||
id="messagelist__sentinel"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="jumpback jumpback__hide"
|
||||
id="jumpback_button"
|
||||
>
|
||||
<div
|
||||
class="jumpback__messages"
|
||||
onClick={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
>
|
||||
Jump Back
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="activechatchannel__alerts"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<div className="activechatchannel">
|
||||
<div className="activechatchannel__conversation">
|
||||
{channelHeader}
|
||||
<div className="activechatchannel__messages" id="messagelist">
|
||||
<div
|
||||
className="activechatchannel__messages"
|
||||
onScroll={this.handleMessageScroll}
|
||||
ref={scroller => {
|
||||
this.scroller = scroller;
|
||||
}}
|
||||
id="messagelist"
|
||||
>
|
||||
{this.renderMessages()}
|
||||
{incomingCall}
|
||||
<div className="messagelist__sentinel" id="messagelist__sentinel" />
|
||||
</div>
|
||||
<div className="jumpback jumpback__hide" id="jumpback_button">
|
||||
<div
|
||||
role="button"
|
||||
className="jumpback__messages"
|
||||
onClick={this.jumpBacktoBottom}
|
||||
tabIndex="0"
|
||||
onKeyUp={e => {
|
||||
if (e.keyCode === 13) this.jumpBacktoBottom();
|
||||
}}
|
||||
>
|
||||
Jump Back
|
||||
</div>
|
||||
</div>
|
||||
<div className="activechatchannel__alerts">
|
||||
<Alert showAlert={state.showAlert} />
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue