mirror of
https://github.com/lux-tel/session-desktop.git
synced 2026-10-30 20:33:24 +00:00
143 lines
4.1 KiB
TypeScript
143 lines
4.1 KiB
TypeScript
import { isEmpty } from 'lodash';
|
|
import type { CSSProperties } from 'styled-components';
|
|
|
|
import { useConvoIdFromContext } from '../../../contexts/ConvoIdContext';
|
|
import {
|
|
useHasUnread,
|
|
useIsPrivate,
|
|
useIsPublic,
|
|
useIsTyping,
|
|
useLastMessage,
|
|
} from '../../../hooks/useParamSelector';
|
|
import { LastMessageStatusType } from '../../../state/ducks/types';
|
|
import { useIsSearchingForType } from '../../../state/selectors/search';
|
|
import { useIsMessageRequestOverlayShown } from '../../../state/selectors/section';
|
|
import { assertUnreachable } from '../../../types/sqlSharedTypes';
|
|
import { TypingAnimation } from '../../conversation/TypingAnimation';
|
|
import { MessageBody } from '../../conversation/message/message-content/MessageBody';
|
|
import { InteractionItem } from './InteractionItem';
|
|
import { LucideIcon } from '../../icon/LucideIcon';
|
|
import { LUCIDE_ICONS_UNICODE } from '../../icon/lucide';
|
|
import { useSelectedConversationKey } from '../../../state/selectors/selectedConversation';
|
|
|
|
export function getStyleForMessageItemText(
|
|
hasUnread: boolean,
|
|
isSelectedConvo: boolean
|
|
): CSSProperties {
|
|
return {
|
|
flexGrow: 1,
|
|
flexShrink: 1,
|
|
|
|
fontSize: 'var(--font-size-sm)',
|
|
|
|
overflow: 'hidden',
|
|
whiteSpace: 'nowrap',
|
|
textOverflow: 'ellipsis',
|
|
color: 'var(--conversation-tab-text-color)',
|
|
userSelect: 'none',
|
|
...(hasUnread && {
|
|
fontWeight: '400',
|
|
color: 'var(--conversation-tab-text-unread-color)',
|
|
}),
|
|
...(isSelectedConvo && {
|
|
color: 'var(--conversation-tab-text-selected-color)',
|
|
}),
|
|
};
|
|
}
|
|
|
|
export const MessageItem = () => {
|
|
const conversationId = useConvoIdFromContext();
|
|
const lastMessage = useLastMessage(conversationId);
|
|
const isGroup = !useIsPrivate(conversationId);
|
|
const isPublic = useIsPublic(conversationId);
|
|
|
|
const hasUnread = useHasUnread(conversationId);
|
|
const isConvoTyping = useIsTyping(conversationId);
|
|
const isMessageRequest = useIsMessageRequestOverlayShown();
|
|
|
|
const isSearching = useIsSearchingForType('global');
|
|
|
|
const isSelectedConvo = useSelectedConversationKey() === conversationId;
|
|
|
|
if (lastMessage?.interactionType && lastMessage?.interactionStatus) {
|
|
return <InteractionItem conversationId={conversationId} lastMessage={lastMessage} />;
|
|
}
|
|
|
|
if (!lastMessage && !isConvoTyping) {
|
|
return null;
|
|
}
|
|
|
|
const text = lastMessage?.text || '';
|
|
|
|
if (isEmpty(text)) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<div className="module-conversation-list-item__message">
|
|
<div style={getStyleForMessageItemText(hasUnread, isSelectedConvo)}>
|
|
{isConvoTyping ? (
|
|
<TypingAnimation />
|
|
) : (
|
|
<MessageBody
|
|
text={text}
|
|
disableJumbomoji={true}
|
|
disableRichContent={true}
|
|
isGroup={isGroup}
|
|
isPublic={isPublic}
|
|
/>
|
|
)}
|
|
</div>
|
|
{!isSearching && lastMessage && lastMessage.status && !isMessageRequest ? (
|
|
<IconMessageStatus status={lastMessage.status} />
|
|
) : null}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
function IconMessageStatus({ status }: { status: LastMessageStatusType }) {
|
|
const nonErrorIconColor = 'var(--text-secondary-color)';
|
|
switch (status) {
|
|
case 'error':
|
|
return (
|
|
<LucideIcon
|
|
unicode={LUCIDE_ICONS_UNICODE.TRIANGLE_ALERT}
|
|
iconColor={'var(--danger-color)'}
|
|
iconSize="small"
|
|
style={{ flexShrink: 0 }}
|
|
/>
|
|
);
|
|
case 'read':
|
|
return (
|
|
<LucideIcon
|
|
unicode={LUCIDE_ICONS_UNICODE.EYE}
|
|
iconColor={nonErrorIconColor}
|
|
iconSize="small"
|
|
style={{ flexShrink: 0 }}
|
|
/>
|
|
);
|
|
case 'sending':
|
|
return (
|
|
<LucideIcon
|
|
unicode={LUCIDE_ICONS_UNICODE.CIRCLE_ELLIPSES}
|
|
iconColor={nonErrorIconColor}
|
|
iconSize="small"
|
|
style={{ flexShrink: 0 }}
|
|
/>
|
|
);
|
|
case 'sent':
|
|
return (
|
|
<LucideIcon
|
|
unicode={LUCIDE_ICONS_UNICODE.CIRCLE_CHECK}
|
|
iconColor={nonErrorIconColor}
|
|
iconSize="small"
|
|
style={{ flexShrink: 0 }}
|
|
/>
|
|
);
|
|
case undefined:
|
|
return null;
|
|
default:
|
|
assertUnreachable(status, 'missing case error');
|
|
}
|
|
}
|