import React from 'react'; import { Avatar } from '../Avatar'; import { Colors, LocalizerType } from '../../types/Util'; import { ContextMenu, ContextMenuTrigger, MenuItem, SubMenu, } from 'react-contextmenu'; import { SessionIconButton, SessionIconSize, SessionIconType, } from '../session/icon'; import { SessionButton, SessionButtonColor, SessionButtonType, } from '../session/SessionButton'; export interface TimerOption { name: string; value: number; } interface Props { id: string; name?: string; phoneNumber: string; profileName?: string; avatarPath?: string; isVerified: boolean; isMe: boolean; isClosable?: boolean; isGroup: boolean; isArchived: boolean; isPublic: boolean; isRss: boolean; amMod: boolean; // We might not always have the full list of members, // e.g. for open groups where we could have thousands // of members. We'll keep this for now (for closed chats) members: Array; // not equal members.length (see above) subscriberCount?: number; expirationSettingName?: string; showBackButton: boolean; timerOptions: Array; hasNickname?: boolean; isBlocked: boolean; isFriend: boolean; isFriendRequestPending: boolean; isOnline?: boolean; selectedMessages: any; onSetDisappearingMessages: (seconds: number) => void; onDeleteMessages: () => void; onDeleteContact: () => void; onResetSession: () => void; onCloseOverlay: () => void; onDeleteSelectedMessages: () => void; onArchive: () => void; onMoveToInbox: () => void; onShowSafetyNumber: () => void; onShowAllMedia: () => void; onShowGroupMembers: () => void; onGoBack: () => void; onBlockUser: () => void; onUnblockUser: () => void; onClearNickname: () => void; onChangeNickname: () => void; onCopyPublicKey: () => void; onLeaveGroup: () => void; onAddModerators: () => void; onRemoveModerators: () => void; onInviteFriends: () => void; onAvatarClick?: (userPubKey: string) => void; onUpdateGroupName: () => void; i18n: LocalizerType; } export class ConversationHeader extends React.Component { public showMenuBound: (event: React.MouseEvent) => void; public onAvatarClickBound: (userPubKey: string) => void; public menuTriggerRef: React.RefObject; public constructor(props: Props) { super(props); this.menuTriggerRef = React.createRef(); this.showMenuBound = this.showMenu.bind(this); this.onAvatarClickBound = this.onAvatarClick.bind(this); } public showMenu(event: React.MouseEvent) { if (this.menuTriggerRef.current) { this.menuTriggerRef.current.handleContextClick(event); } } public renderBackButton() { const { onGoBack, showBackButton } = this.props; if (!showBackButton) { return null; } return (
); } public renderTitle() { const { phoneNumber, i18n, profileName, isFriend, isGroup, isPublic, isRss, members, subscriberCount, isFriendRequestPending, isMe, name, } = this.props; if (isMe) { return (
{i18n('noteToSelf')}
); } const memberCount: number = (() => { if (!isGroup || isRss) { return 0; } if (isPublic) { return subscriberCount || 0; } else { return members.length; } })(); let text = ''; if (isFriendRequestPending) { text = i18n('pendingAcceptance'); } else if (!isFriend && !isGroup) { text = i18n('notFriends'); } else if (memberCount > 0) { const count = String(memberCount); text = i18n('members', [count]); } const textEl = text === '' ? null : ( {text} ); let title; if (profileName) { title = `${profileName} ${window.shortenPubkey(phoneNumber)}`; } else { if (name) { title = `${name}`; } else { title = `User ${window.shortenPubkey(phoneNumber)}`; } } return (
{title} {textEl}
); } public renderAvatar() { const { avatarPath, i18n, isGroup, isMe, name, phoneNumber, profileName, isOnline, } = this.props; const borderColor = isOnline ? Colors.ONLINE : Colors.OFFLINE_LIGHT; const conversationType = isGroup ? 'group' : 'direct'; return ( { this.onAvatarClickBound(phoneNumber); }} /> ); } public renderExpirationLength() { const { expirationSettingName } = this.props; if (!expirationSettingName) { return null; } return (
{expirationSettingName}
); } public renderSearch() { return (
); } public renderOptions(triggerId: string) { const { showBackButton } = this.props; if (showBackButton) { return null; } return ( ); } public renderMenu(triggerId: string) { const { i18n, isMe, isClosable, isPublic, isRss, isGroup, amMod, onDeleteMessages, onDeleteContact, onCopyPublicKey, onLeaveGroup, onAddModerators, onRemoveModerators, onInviteFriends, onUpdateGroupName, } = this.props; const isPrivateGroup = isGroup && !isPublic && !isRss; const copyIdLabel = isGroup ? i18n('copyChatId') : i18n('copyPublicKey'); return ( {this.renderPublicMenuItems()} {!isRss ? ( {copyIdLabel} ) : null} {i18n('deleteMessages')} {amMod ? ( {i18n('addModerators')} ) : null} {amMod ? ( {i18n('removeModerators')} ) : null} {amMod ? ( {i18n('editGroupNameOrPicture')} ) : null} {isPrivateGroup ? ( {i18n('leaveGroup')} ) : null} {/* TODO: add delete group */} {isGroup && isPublic ? ( {i18n('inviteFriends')} ) : null} {!isMe && isClosable && !isPrivateGroup ? ( !isPublic ? ( {i18n('deleteContact')} ) : ( {i18n('deletePublicChannel')} ) ) : null} ); } public renderSelectionOverlay() { const { onDeleteSelectedMessages, onCloseOverlay, i18n } = this.props; return (
); } public render() { const { id } = this.props; const triggerId = `conversation-${id}-${Date.now()}`; return ( <> {this.renderSelectionOverlay()}
{this.renderBackButton()}
{this.renderOptions(triggerId)} {this.renderTitle()} {/* This might be redundant as we show the title in the title: */} {/*isPrivateGroup ? this.renderMemberCount() : null*/}
{this.renderExpirationLength()} {!this.props.isRss && this.renderAvatar()} {this.renderMenu(triggerId)}
); } public onAvatarClick(userPubKey: string) { if (this.props.onAvatarClick) { this.props.onAvatarClick(userPubKey); } } public highlightMessageSearch() { // This is a temporary fix. In future we want to search // messages in the current conversation $('.session-search-input input').focus(); } private renderPublicMenuItems() { const { i18n, isBlocked, isMe, isGroup, isArchived, isPublic, isRss, onResetSession, onSetDisappearingMessages, // onShowAllMedia, onShowGroupMembers, onShowSafetyNumber, onArchive, onMoveToInbox, timerOptions, onBlockUser, onUnblockUser, hasNickname, onClearNickname, onChangeNickname, } = this.props; if (isPublic || isRss) { return null; } const disappearingTitle = i18n('disappearingMessages') as any; const blockTitle = isBlocked ? i18n('unblockUser') : i18n('blockUser'); const blockHandler = isBlocked ? onUnblockUser : onBlockUser; const disappearingMessagesMenuItem = ( {(timerOptions || []).map(item => ( { onSetDisappearingMessages(item.value); }} > {item.name} ))} ); const showMembersMenuItem = isGroup && ( {i18n('showMembers')} ); const showSafetyNumberMenuItem = !isGroup && !isMe && ( {i18n('showSafetyNumber')} ); const resetSessionMenuItem = !isGroup && ( {i18n('resetSession')} ); const blockHandlerMenuItem = !isMe && !isGroup && !isRss && {blockTitle}; const changeNicknameMenuItem = !isMe && !isGroup && ( {i18n('changeNickname')} ); const clearNicknameMenuItem = !isMe && !isGroup && hasNickname && ( {i18n('clearNickname')} ); const archiveConversationMenuItem = isArchived ? ( {i18n('moveConversationToInbox')} ) : ( {i18n('archiveConversation')} ); return ( {/* {i18n('viewAllMedia')} */} {disappearingMessagesMenuItem} {showMembersMenuItem} {showSafetyNumberMenuItem} {resetSessionMenuItem} {blockHandlerMenuItem} {changeNicknameMenuItem} {clearNicknameMenuItem} {archiveConversationMenuItem} ); } }