You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-desktop/ts/components/conversation/SessionMessagesList.tsx

164 lines
5.3 KiB
TypeScript

import { useLayoutEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import useKey from 'react-use/lib/useKey';
import {
getOldBottomMessageId,
getOldTopMessageId,
getSortedMessagesTypesOfSelectedConversation,
} from '../../state/selectors/conversations';
import { useSelectedConversationKey } from '../../state/selectors/selectedConversation';
import { MessageDateBreak } from './message/message-item/DateBreak';
import { CommunityInvitation } from './message/message-item/GroupInvitation';
import { GroupUpdateMessage } from './message/message-item/GroupUpdateMessage';
import { Message } from './message/message-item/Message';
import { MessageRequestResponse } from './message/message-item/MessageRequestResponse';
import { CallNotification } from './message/message-item/notification-bubble/CallNotification';
import { IsDetailMessageViewContext } from '../../contexts/isDetailViewContext';
import { SessionLastSeenIndicator } from './SessionLastSeenIndicator';
import { TimerNotification } from './TimerNotification';
import { DataExtractionNotification } from './message/message-item/DataExtractionNotification';
import { InteractionNotification } from './message/message-item/InteractionNotification';
import { assertUnreachable } from '../../types/sqlSharedTypes';
import type { WithMessageId } from '../../session/types/with';
function isNotTextboxEvent(e: KeyboardEvent) {
return (e?.target as any)?.type === undefined;
}
let previousRenderedConvo: string | undefined;
export const SessionMessagesList = (props: {
scrollAfterLoadMore: (
messageIdToScrollTo: string,
type: 'load-more-top' | 'load-more-bottom'
) => void;
onPageUpPressed: () => void;
onPageDownPressed: () => void;
onHomePressed: () => void;
onEndPressed: () => void;
}) => {
const messagesProps = useSelector(getSortedMessagesTypesOfSelectedConversation);
const convoKey = useSelectedConversationKey();
const [didScroll, setDidScroll] = useState(false);
const oldTopMessageId = useSelector(getOldTopMessageId);
const oldBottomMessageId = useSelector(getOldBottomMessageId);
useLayoutEffect(() => {
const newTopMessageId = messagesProps.length
? messagesProps[messagesProps.length - 1].messageId
: undefined;
if (oldTopMessageId !== newTopMessageId && oldTopMessageId && newTopMessageId) {
props.scrollAfterLoadMore(oldTopMessageId, 'load-more-top');
}
const newBottomMessageId = messagesProps.length ? messagesProps[0].messageId : undefined;
if (newBottomMessageId !== oldBottomMessageId && oldBottomMessageId && newBottomMessageId) {
props.scrollAfterLoadMore(oldBottomMessageId, 'load-more-bottom');
}
});
useKey('PageUp', () => {
props.onPageUpPressed();
});
useKey('PageDown', () => {
props.onPageDownPressed();
});
useKey('Home', e => {
if (isNotTextboxEvent(e)) {
props.onHomePressed();
}
});
useKey('End', e => {
if (isNotTextboxEvent(e)) {
props.onEndPressed();
}
});
if (didScroll && previousRenderedConvo !== convoKey) {
setDidScroll(false);
previousRenderedConvo = convoKey;
}
return (
<IsDetailMessageViewContext.Provider value={false}>
{messagesProps.map(messageProps => {
const { messageId } = messageProps;
let ComponentToRender: React.FC<WithMessageId> | undefined;
switch (messageProps.message.messageType) {
case 'group-notification': {
ComponentToRender = GroupUpdateMessage;
break;
}
case 'group-invitation': {
ComponentToRender = CommunityInvitation;
break;
}
case 'message-request-response': {
ComponentToRender = MessageRequestResponse;
break;
}
case 'data-extraction': {
ComponentToRender = DataExtractionNotification;
break;
}
case 'timer-notification': {
ComponentToRender = TimerNotification;
break;
}
case 'call-notification': {
ComponentToRender = CallNotification;
break;
}
case 'interaction-notification': {
ComponentToRender = InteractionNotification;
break;
}
case 'regular-message': {
ComponentToRender = Message;
break;
}
default:
assertUnreachable(
messageProps.message.messageType,
`unhandled case with ${messageProps.message.messageType}`
);
}
const unreadIndicator = messageProps.showUnreadIndicator ? (
<SessionLastSeenIndicator
key={'unread-indicator'}
messageId={messageId}
didScroll={didScroll}
setDidScroll={setDidScroll}
/>
) : null;
const dateBreak =
messageProps.showDateBreak !== undefined ? (
<MessageDateBreak
key={`date-break-${messageId}`}
timestamp={messageProps.showDateBreak}
messageId={messageId}
/>
) : null;
return [
<ComponentToRender key={messageId} messageId={messageId} />,
unreadIndicator,
dateBreak,
];
})}
</IsDetailMessageViewContext.Provider>
);
};