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.
164 lines
5.3 KiB
TypeScript
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>
|
|
);
|
|
};
|