mirror of
https://github.com/lux-tel/session-desktop.git
synced 2026-10-30 20:33:24 +00:00
219 lines
6.1 KiB
TypeScript
219 lines
6.1 KiB
TypeScript
import { MouseEvent } from 'react';
|
|
import clsx from 'clsx';
|
|
import styled from 'styled-components';
|
|
import { useConvoIdFromContext } from '../../../contexts/ConvoIdContext';
|
|
import { Data } from '../../../data/data';
|
|
import {
|
|
useActiveAt,
|
|
useHasUnread,
|
|
useIsForcedUnreadWithoutUnreadMsg,
|
|
useIsPinned,
|
|
useMentionedUs,
|
|
useNotificationSetting,
|
|
useUnreadCount,
|
|
} from '../../../hooks/useParamSelector';
|
|
import { Constants } from '../../../session';
|
|
import {
|
|
openConversationToSpecificMessage,
|
|
openConversationWithMessages,
|
|
} from '../../../state/ducks/conversations';
|
|
import { useIsSearchingForType } from '../../../state/selectors/search';
|
|
import { Timestamp } from '../../conversation/Timestamp';
|
|
import { SessionIcon } from '../../icon';
|
|
import { UserItem } from './UserItem';
|
|
import type { WithConvoId } from '../../../session/types/with';
|
|
|
|
const NotificationSettingIcon = () => {
|
|
const convoId = useConvoIdFromContext();
|
|
const convoSetting = useNotificationSetting(convoId);
|
|
|
|
switch (convoSetting) {
|
|
case 'all':
|
|
return null;
|
|
case 'disabled':
|
|
return (
|
|
<SessionIcon
|
|
iconType="mute"
|
|
iconColor={'var(--conversation-tab-text-color)'}
|
|
iconSize="small"
|
|
style={{ flexShrink: 0 }}
|
|
/>
|
|
);
|
|
case 'mentions_only':
|
|
return (
|
|
<SessionIcon
|
|
iconType="bell"
|
|
iconColor={'var(--conversation-tab-text-color)'}
|
|
iconSize="small"
|
|
style={{ flexShrink: 0 }}
|
|
/>
|
|
);
|
|
default:
|
|
return null;
|
|
}
|
|
};
|
|
|
|
const StyledConversationListItemIconWrapper = styled.div`
|
|
display: flex;
|
|
flex-direction: row;
|
|
gap: var(--margins-xs);
|
|
`;
|
|
|
|
const PinIcon = () => {
|
|
const conversationId = useConvoIdFromContext();
|
|
|
|
const isPinned = useIsPinned(conversationId);
|
|
|
|
return isPinned ? (
|
|
<SessionIcon
|
|
iconType="pin"
|
|
iconColor={'var(--conversation-tab-text-color)'}
|
|
iconSize="small"
|
|
style={{ flexShrink: 0 }}
|
|
/>
|
|
) : null;
|
|
};
|
|
|
|
const ListItemIcons = ({ conversationId }: WithConvoId) => {
|
|
const isSearching = useIsSearchingForType('global');
|
|
|
|
if (isSearching) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<StyledConversationListItemIconWrapper>
|
|
<PinIcon />
|
|
<NotificationSettingIcon />
|
|
<UnreadCount conversationId={conversationId} />
|
|
<AtSymbol conversationId={conversationId} />
|
|
</StyledConversationListItemIconWrapper>
|
|
);
|
|
};
|
|
|
|
const MentionAtSymbol = styled.span`
|
|
background: var(--unread-messages-alert-background-color);
|
|
color: var(--unread-messages-alert-text-color);
|
|
text-align: center;
|
|
margin-top: 0px;
|
|
margin-bottom: 0px;
|
|
position: static;
|
|
|
|
font-weight: 700;
|
|
font-size: var(--font-size-xs);
|
|
letter-spacing: 0.25px;
|
|
|
|
height: 16px;
|
|
min-width: 16px;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
flex-shrink: 0;
|
|
|
|
&:hover {
|
|
filter: grayscale(0.7);
|
|
}
|
|
`;
|
|
|
|
/**
|
|
* When clicking on the `@` symbol of a conversation, we open the conversation to the first unread message tagging us (with the @pubkey syntax)
|
|
*/
|
|
async function openConvoToLastMention(e: MouseEvent<HTMLSpanElement>, conversationId: string) {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
|
|
// mousedown is invoked sooner than onClick, but for both right and left click
|
|
if (e.button === 0) {
|
|
const oldestMessageUnreadWithMention =
|
|
(await Data.getFirstUnreadMessageWithMention(conversationId)) || null;
|
|
if (oldestMessageUnreadWithMention) {
|
|
await openConversationToSpecificMessage({
|
|
conversationKey: conversationId,
|
|
messageIdToNavigateTo: oldestMessageUnreadWithMention,
|
|
shouldHighlightMessage: true,
|
|
});
|
|
} else {
|
|
window.log.info('cannot open to latest mention as no unread mention are found');
|
|
await openConversationWithMessages({
|
|
conversationKey: conversationId,
|
|
messageId: null,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
const AtSymbol = ({ conversationId }: WithConvoId) => {
|
|
const hasMentionedUs = useMentionedUs(conversationId);
|
|
const hasUnread = useHasUnread(conversationId);
|
|
|
|
return hasMentionedUs && hasUnread ? (
|
|
<MentionAtSymbol
|
|
title="Open to latest mention"
|
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
onMouseDown={async e => openConvoToLastMention(e, conversationId)}
|
|
>
|
|
@
|
|
</MentionAtSymbol>
|
|
) : null;
|
|
};
|
|
|
|
const StyledUnreadCount = styled.p`
|
|
background-color: var(--unread-messages-alert-background-color);
|
|
text-align: center;
|
|
padding-top: 1px;
|
|
font-size: var(--font-size-xs);
|
|
letter-spacing: 0.25px;
|
|
height: 16px;
|
|
min-width: 16px;
|
|
line-height: 16px;
|
|
border-radius: 8px;
|
|
color: var(--unread-messages-alert-text-color);
|
|
font-weight: 700;
|
|
margin: 0px;
|
|
padding-inline: 3px;
|
|
flex-shrink: 0;
|
|
`;
|
|
|
|
const UnreadCount = ({ conversationId }: WithConvoId) => {
|
|
const unreadMsgCount = useUnreadCount(conversationId);
|
|
const forcedUnread = useIsForcedUnreadWithoutUnreadMsg(conversationId);
|
|
|
|
const unreadWithOverflow =
|
|
unreadMsgCount > Constants.CONVERSATION.MAX_CONVO_UNREAD_COUNT
|
|
? `${Constants.CONVERSATION.MAX_CONVO_UNREAD_COUNT}+`
|
|
: unreadMsgCount || ' ';
|
|
|
|
// TODO would be good to merge the style of this with SessionNotificationCount or SessionUnreadCount at some point.
|
|
return unreadMsgCount > 0 || forcedUnread ? (
|
|
<StyledUnreadCount>{unreadWithOverflow}</StyledUnreadCount>
|
|
) : null;
|
|
};
|
|
|
|
export const ConversationListItemHeaderItem = () => {
|
|
const conversationId = useConvoIdFromContext();
|
|
|
|
const isSearching = useIsSearchingForType('global');
|
|
|
|
const hasUnread = useHasUnread(conversationId);
|
|
const activeAt = useActiveAt(conversationId);
|
|
|
|
return (
|
|
<div className="module-conversation-list-item__header">
|
|
<div className={clsx('module-conversation-list-item__header__name')}>
|
|
<UserItem />
|
|
</div>
|
|
<ListItemIcons conversationId={conversationId} />
|
|
|
|
{!isSearching && (
|
|
<div
|
|
className={clsx(
|
|
'module-conversation-list-item__header__date',
|
|
hasUnread ? 'module-conversation-list-item__header__date--has-unread' : null
|
|
)}
|
|
>
|
|
<Timestamp timestamp={activeAt} isConversationSearchResult={false} />
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|