// Copyright 2018-2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; import moment from 'moment'; import classNames from 'classnames'; import { ContextMenu, ContextMenuTrigger, MenuItem, SubMenu, } from 'react-contextmenu'; import { Emojify } from './Emojify'; import { Avatar, AvatarSize } from '../Avatar'; import { InContactsIcon } from '../InContactsIcon'; import { LocalizerType } from '../../types/Util'; import { ColorType } from '../../types/Colors'; import { getMuteOptions } from '../../util/getMuteOptions'; import { ExpirationTimerOptions, TimerOption, } from '../../util/ExpirationTimerOptions'; import { isMuted } from '../../util/isMuted'; import { missingCaseError } from '../../util/missingCaseError'; export enum OutgoingCallButtonStyle { None, JustVideo, Both, Join, } export type PropsDataType = { id: string; name?: string; phoneNumber?: string; profileName?: string; color?: ColorType; avatarPath?: string; type: 'direct' | 'group'; title: string; acceptedMessageRequest?: boolean; isVerified?: boolean; isMe?: boolean; isArchived?: boolean; isPinned?: boolean; isMissingMandatoryProfileSharing?: boolean; left?: boolean; markedUnread?: boolean; canChangeTimer?: boolean; expireTimer?: number; muteExpiresAt?: number; showBackButton?: boolean; outgoingCallButtonStyle: OutgoingCallButtonStyle; }; export type PropsActionsType = { onSetMuteNotifications: (seconds: number) => void; onSetDisappearingMessages: (seconds: number) => void; onDeleteMessages: () => void; onResetSession: () => void; onSearchInConversation: () => void; onOutgoingAudioCallInConversation: () => void; onOutgoingVideoCallInConversation: () => void; onSetPin: (value: boolean) => void; onShowSafetyNumber: () => void; onShowAllMedia: () => void; onShowGroupMembers: () => void; onGoBack: () => void; onArchive: () => void; onMarkUnread: () => void; onMoveToInbox: () => void; }; export type PropsHousekeepingType = { i18n: LocalizerType; }; export type PropsType = PropsDataType & PropsActionsType & PropsHousekeepingType; export class ConversationHeader extends React.Component { public showMenuBound: (event: React.MouseEvent) => void; // Comes from a third-party dependency // eslint-disable-next-line @typescript-eslint/no-explicit-any public menuTriggerRef: React.RefObject; public constructor(props: PropsType) { super(props); this.menuTriggerRef = React.createRef(); this.showMenuBound = this.showMenu.bind(this); } public showMenu(event: React.MouseEvent): void { if (this.menuTriggerRef.current) { this.menuTriggerRef.current.handleContextClick(event); } } public renderBackButton(): JSX.Element { const { i18n, onGoBack, showBackButton } = this.props; return ( ); default: throw missingCaseError(outgoingCallButtonStyle); } } public renderMenu(triggerId: string): JSX.Element { const { i18n, acceptedMessageRequest, canChangeTimer, isArchived, isMe, isPinned, type, markedUnread, muteExpiresAt, isMissingMandatoryProfileSharing, left, onDeleteMessages, onResetSession, onSetDisappearingMessages, onSetMuteNotifications, onShowAllMedia, onShowGroupMembers, onShowSafetyNumber, onArchive, onMarkUnread, onSetPin, onMoveToInbox, } = this.props; const muteOptions = []; if (isMuted(muteExpiresAt)) { const expires = moment(muteExpiresAt); const muteExpirationLabel = moment().isSame(expires, 'day') ? expires.format('hh:mm A') : expires.format('M/D/YY, hh:mm A'); muteOptions.push( ...[ { name: i18n('muteExpirationLabel', [muteExpirationLabel]), disabled: true, value: 0, }, { name: i18n('unmute'), value: 0, }, ] ); } muteOptions.push(...getMuteOptions(i18n)); // eslint-disable-next-line @typescript-eslint/no-explicit-any const disappearingTitle = i18n('disappearingMessages') as any; // eslint-disable-next-line @typescript-eslint/no-explicit-any const muteTitle = i18n('muteNotificationsTitle') as any; const isGroup = type === 'group'; const disableTimerChanges = Boolean( !canChangeTimer || !acceptedMessageRequest || left || isMissingMandatoryProfileSharing ); return ( {disableTimerChanges ? null : ( {ExpirationTimerOptions.map((item: typeof TimerOption) => ( { onSetDisappearingMessages(item.get('seconds')); }} > {item.getName(i18n)} ))} )} {muteOptions.map(item => ( { onSetMuteNotifications(item.value); }} > {item.name} ))} {isGroup ? ( {i18n('showMembers')} ) : null} {i18n('viewRecentMedia')} {!isGroup && !isMe ? ( {i18n('showSafetyNumber')} ) : null} {!isGroup && acceptedMessageRequest ? ( {i18n('resetSession')} ) : null} {!markedUnread ? ( {i18n('markUnread')} ) : null} {isArchived ? ( {i18n('moveConversationToInbox')} ) : ( {i18n('archiveConversation')} )} {i18n('deleteMessages')} {isPinned ? ( onSetPin(false)}> {i18n('unpinConversation')} ) : ( onSetPin(true)}> {i18n('pinConversation')} )} ); } public render(): JSX.Element { const { id } = this.props; const triggerId = `conversation-${id}`; return (
{this.renderBackButton()}
{this.renderAvatar()} {this.renderTitle()}
{this.renderExpirationLength()} {this.renderOutgoingCallButtons()} {this.renderSearchButton()} {this.renderMoreButton(triggerId)} {this.renderMenu(triggerId)}
); } }