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/message/message-content/MessageAvatar.tsx

151 lines
5.4 KiB
TypeScript

import React, { useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import styled from 'styled-components';
import { OpenGroupData } from '../../../../data/opengroups';
import { MessageRenderingProps } from '../../../../models/messageType';
import { findCachedBlindedMatchOrLookItUp } from '../../../../session/apis/open_group_api/sogsv3/knownBlindedkeys';
import { getConversationController } from '../../../../session/conversations';
import { getSodiumRenderer } from '../../../../session/crypto';
import { KeyPrefixType, PubKey } from '../../../../session/types';
import { openConversationWithMessages } from '../../../../state/ducks/conversations';
import { updateUserDetailsModal } from '../../../../state/ducks/modalDialog';
import {
useAuthorAvatarPath,
useAuthorName,
useAuthorProfileName,
useLastMessageOfSeries,
useMessageAuthor,
useMessageSenderIsAdmin,
} from '../../../../state/selectors';
import {
getSelectedCanWrite,
useSelectedConversationKey,
useSelectedIsPublic,
} from '../../../../state/selectors/selectedConversation';
import { Avatar, AvatarSize, CrownIcon } from '../../../avatar/Avatar';
const StyledAvatar = styled.div`
position: relative;
margin-inline-end: 20px;
padding-bottom: 6px;
padding-inline-end: 4px;
`;
export type MessageAvatarSelectorProps = Pick<
MessageRenderingProps,
'sender' | 'isSenderAdmin' | 'lastMessageOfSeries'
>;
type Props = { messageId: string; hideAvatar: boolean; isPrivate: boolean };
export const MessageAvatar = (props: Props) => {
const { messageId, hideAvatar, isPrivate } = props;
const dispatch = useDispatch();
const selectedConvoKey = useSelectedConversationKey();
const isTypingEnabled = useSelector(getSelectedCanWrite);
const isPublic = useSelectedIsPublic();
const authorName = useAuthorName(messageId);
const authorProfileName = useAuthorProfileName(messageId);
const authorAvatarPath = useAuthorAvatarPath(messageId);
const sender = useMessageAuthor(messageId);
const lastMessageOfSeries = useLastMessageOfSeries(messageId);
const isSenderAdmin = useMessageSenderIsAdmin(messageId);
const userName = authorName || authorProfileName || sender;
const onMessageAvatarClick = useCallback(async () => {
if (!sender) {
return;
}
if (isPublic && !PubKey.isBlinded(sender)) {
// public chat but session id not blinded. disable showing user details if we do not have an active convo with that user.
// an unactive convo with that user means that we never chatted with that id directyly, but only through a sogs
const convoWithSender = getConversationController().get(sender);
if (!convoWithSender || !convoWithSender.get('active_at')) {
// for some time, we might still get some unblinded messages, as in message sent unblinded because
// * older clients still send unblinded message and those are allowed by sogs if they doesn't enforce blinding
// * new clients still send unblinded message and those are allowed by sogs if it doesn't enforce blinding
// we want to not allow users to open user details dialog when that's the case.
// to handle this case, we can drop the click on avatar if the conversation with that user is not active.
window.log.info(
'onMessageAvatarClick: public unblinded message and sender convo is not active. Dropping click event'
);
return;
}
}
if (isPublic && !isTypingEnabled) {
window.log.info('onMessageAvatarClick: typing is disabled...');
return;
}
if (isPublic && selectedConvoKey) {
if (sender.startsWith(KeyPrefixType.blinded25)) {
window.log.info('onMessageAvatarClick: blinded25 convo click are disabled currently...');
return;
}
const convoOpen = getConversationController().get(selectedConvoKey);
const room = OpenGroupData.getV2OpenGroupRoom(convoOpen.id);
let privateConvoToOpen = sender;
if (room?.serverPublicKey) {
const foundRealSessionId = await findCachedBlindedMatchOrLookItUp(
sender,
room.serverPublicKey,
await getSodiumRenderer()
);
privateConvoToOpen = foundRealSessionId || privateConvoToOpen;
}
await getConversationController()
.get(privateConvoToOpen)
.setOriginConversationID(selectedConvoKey);
// public and blinded key for that message, we should open the convo as is and see if the user wants
// to send a sogs blinded message request.
await openConversationWithMessages({ conversationKey: privateConvoToOpen, messageId: null });
return;
}
// not public, i.e. closed group. Just open dialog for the user to do what he wants
dispatch(
updateUserDetailsModal({
conversationId: sender,
userName: userName || '',
authorAvatarPath,
})
);
}, [dispatch, isTypingEnabled, userName, sender, isPublic, authorAvatarPath, selectedConvoKey]);
if (!sender) {
return null;
}
if (isPrivate) {
return null;
}
if (!lastMessageOfSeries) {
return <div style={{ marginInlineEnd: '60px' }} key={`msg-avatar-${sender}`} />;
}
return (
<StyledAvatar
key={`msg-avatar-${sender}`}
style={{
visibility: hideAvatar ? 'hidden' : undefined,
}}
>
<Avatar
size={AvatarSize.S}
onAvatarClick={() => void onMessageAvatarClick()}
pubkey={sender}
/>
{isSenderAdmin && <CrownIcon />}
</StyledAvatar>
);
};