2021-08-04 12:52:59 +03:00
|
|
|
/* eslint-disable react/prop-types */
|
|
|
|
import React, { useState, useEffect } from 'react';
|
|
|
|
import PropTypes from 'prop-types';
|
2021-08-31 16:13:31 +03:00
|
|
|
import './RoomViewFloating.scss';
|
2021-08-04 12:52:59 +03:00
|
|
|
|
|
|
|
import initMatrix from '../../../client/initMatrix';
|
|
|
|
import cons from '../../../client/state/cons';
|
|
|
|
|
|
|
|
import Text from '../../atoms/text/Text';
|
2021-12-03 15:02:10 +02:00
|
|
|
import Button from '../../atoms/button/Button';
|
2021-08-04 12:52:59 +03:00
|
|
|
import IconButton from '../../atoms/button/IconButton';
|
|
|
|
|
|
|
|
import ChevronBottomIC from '../../../../public/res/ic/outlined/chevron-bottom.svg';
|
2021-12-07 17:34:07 +02:00
|
|
|
import TickMarkIC from '../../../../public/res/ic/outlined/tick-mark.svg';
|
2021-08-04 12:52:59 +03:00
|
|
|
|
|
|
|
import { getUsersActionJsx } from './common';
|
|
|
|
|
2021-12-03 15:02:10 +02:00
|
|
|
function useJumpToEvent(roomTimeline) {
|
|
|
|
const [eventId, setEventId] = useState(null);
|
|
|
|
|
|
|
|
const jumpToEvent = () => {
|
|
|
|
roomTimeline.loadEventTimeline(eventId);
|
|
|
|
};
|
|
|
|
|
2021-12-07 17:34:07 +02:00
|
|
|
const cancelJumpToEvent = (mEvent) => {
|
2021-12-03 15:02:10 +02:00
|
|
|
setEventId(null);
|
2021-12-07 17:34:07 +02:00
|
|
|
if (!mEvent) roomTimeline.markAllAsRead();
|
2021-12-03 15:02:10 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
const readEventId = roomTimeline.getReadUpToEventId();
|
2021-12-07 17:34:07 +02:00
|
|
|
// we only show "Jump to unread" btn only if the event is not in timeline.
|
|
|
|
// if event is in timeline
|
|
|
|
// we will automatically open the timeline from that event position
|
|
|
|
if (!readEventId.startsWith('~') && !roomTimeline.hasEventInTimeline(readEventId)) {
|
2021-12-03 15:02:10 +02:00
|
|
|
setEventId(readEventId);
|
|
|
|
}
|
2021-12-07 17:34:07 +02:00
|
|
|
roomTimeline.on(cons.events.roomTimeline.MARKED_AS_READ, cancelJumpToEvent);
|
2021-12-03 15:02:10 +02:00
|
|
|
|
|
|
|
return () => {
|
2021-12-07 17:34:07 +02:00
|
|
|
roomTimeline.removeListener(cons.events.roomTimeline.MARKED_AS_READ, cancelJumpToEvent);
|
2021-12-03 15:02:10 +02:00
|
|
|
setEventId(null);
|
|
|
|
};
|
|
|
|
}, [roomTimeline]);
|
|
|
|
|
|
|
|
return [!!eventId, jumpToEvent, cancelJumpToEvent];
|
|
|
|
}
|
|
|
|
|
|
|
|
function useTypingMembers(roomTimeline) {
|
2021-08-04 12:52:59 +03:00
|
|
|
const [typingMembers, setTypingMembers] = useState(new Set());
|
2021-12-03 15:02:10 +02:00
|
|
|
|
|
|
|
const updateTyping = (members) => {
|
|
|
|
const mx = initMatrix.matrixClient;
|
|
|
|
members.delete(mx.getUserId());
|
2021-08-04 12:52:59 +03:00
|
|
|
setTypingMembers(members);
|
2021-11-18 10:02:12 +02:00
|
|
|
};
|
2021-08-04 12:52:59 +03:00
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
setTypingMembers(new Set());
|
|
|
|
roomTimeline.on(cons.events.roomTimeline.TYPING_MEMBERS_UPDATED, updateTyping);
|
|
|
|
return () => {
|
|
|
|
roomTimeline?.removeListener(cons.events.roomTimeline.TYPING_MEMBERS_UPDATED, updateTyping);
|
|
|
|
};
|
|
|
|
}, [roomTimeline]);
|
|
|
|
|
2021-12-03 15:02:10 +02:00
|
|
|
return [typingMembers];
|
|
|
|
}
|
|
|
|
|
2021-12-07 17:34:07 +02:00
|
|
|
function useScrollToBottom(roomTimeline) {
|
2021-12-03 15:02:10 +02:00
|
|
|
const [isAtBottom, setIsAtBottom] = useState(true);
|
|
|
|
const handleAtBottom = (atBottom) => setIsAtBottom(atBottom);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
setIsAtBottom(true);
|
2021-12-07 17:34:07 +02:00
|
|
|
roomTimeline.on(cons.events.roomTimeline.AT_BOTTOM, handleAtBottom);
|
|
|
|
return () => roomTimeline.removeListener(cons.events.roomTimeline.AT_BOTTOM, handleAtBottom);
|
|
|
|
}, [roomTimeline]);
|
2021-12-03 15:02:10 +02:00
|
|
|
|
|
|
|
return [isAtBottom, setIsAtBottom];
|
|
|
|
}
|
|
|
|
|
|
|
|
function RoomViewFloating({
|
2021-12-07 17:34:07 +02:00
|
|
|
roomId, roomTimeline,
|
2021-12-03 15:02:10 +02:00
|
|
|
}) {
|
2021-12-07 17:34:07 +02:00
|
|
|
const [isJumpToEvent, jumpToEvent, cancelJumpToEvent] = useJumpToEvent(roomTimeline);
|
2021-12-03 15:02:10 +02:00
|
|
|
const [typingMembers] = useTypingMembers(roomTimeline);
|
2021-12-07 17:34:07 +02:00
|
|
|
const [isAtBottom, setIsAtBottom] = useScrollToBottom(roomTimeline);
|
2021-12-03 15:02:10 +02:00
|
|
|
|
|
|
|
const handleScrollToBottom = () => {
|
2021-12-07 17:34:07 +02:00
|
|
|
roomTimeline.emit(cons.events.roomTimeline.SCROLL_TO_LIVE);
|
2021-12-03 15:02:10 +02:00
|
|
|
setIsAtBottom(true);
|
|
|
|
};
|
|
|
|
|
2021-08-04 12:52:59 +03:00
|
|
|
return (
|
|
|
|
<>
|
2021-12-03 15:02:10 +02:00
|
|
|
<div className={`room-view__unread ${isJumpToEvent ? 'room-view__unread--open' : ''}`}>
|
|
|
|
<Button onClick={jumpToEvent} variant="primary">
|
|
|
|
<Text variant="b2">Jump to unread</Text>
|
|
|
|
</Button>
|
|
|
|
<IconButton
|
|
|
|
onClick={cancelJumpToEvent}
|
|
|
|
variant="primary"
|
|
|
|
size="extra-small"
|
2021-12-07 17:34:07 +02:00
|
|
|
src={TickMarkIC}
|
2021-12-03 15:02:10 +02:00
|
|
|
tooltipPlacement="bottom"
|
2021-12-07 17:34:07 +02:00
|
|
|
tooltip="Mark as read"
|
2021-12-03 15:02:10 +02:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
<div className={`room-view__typing${typingMembers.size > 0 ? ' room-view__typing--open' : ''}`}>
|
2021-09-26 16:17:37 +03:00
|
|
|
<div className="bouncing-loader"><div /></div>
|
2021-12-03 15:02:10 +02:00
|
|
|
<Text variant="b2">{getUsersActionJsx(roomId, [...typingMembers], 'typing...')}</Text>
|
2021-08-04 12:52:59 +03:00
|
|
|
</div>
|
2021-12-03 15:02:10 +02:00
|
|
|
<div className={`room-view__STB${isAtBottom ? '' : ' room-view__STB--open'}`}>
|
2021-08-04 12:52:59 +03:00
|
|
|
<IconButton
|
2021-12-03 15:02:10 +02:00
|
|
|
onClick={handleScrollToBottom}
|
2021-08-04 12:52:59 +03:00
|
|
|
src={ChevronBottomIC}
|
|
|
|
tooltip="Scroll to Bottom"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|
2021-08-31 16:13:31 +03:00
|
|
|
RoomViewFloating.propTypes = {
|
2021-08-04 12:52:59 +03:00
|
|
|
roomId: PropTypes.string.isRequired,
|
|
|
|
roomTimeline: PropTypes.shape({}).isRequired,
|
|
|
|
};
|
|
|
|
|
2021-08-31 16:13:31 +03:00
|
|
|
export default RoomViewFloating;
|