// Copyright 2024 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import React, { type ReactNode, useCallback, useEffect, useMemo } from 'react'; import type { ConversationType } from '../../state/ducks/conversations'; import type { LocalizerType } from '../../types/Util'; import { isInSystemContacts } from '../../util/isInSystemContacts'; import { Avatar, AvatarBlur, AvatarSize } from '../Avatar'; import { Modal } from '../Modal'; import { UserText } from '../UserText'; import { SharedGroupNames } from '../SharedGroupNames'; import { About } from './About'; import { I18n } from '../I18n'; import { canHaveNicknameAndNote } from '../../util/nicknames'; import { Tooltip, TooltipPlacement } from '../Tooltip'; function muted(parts: Array) { return ( {parts} ); } export type PropsType = Readonly<{ i18n: LocalizerType; onClose: () => void; onOpenNotePreviewModal: () => void; conversation: ConversationType; fromOrAddedByTrustedContact?: boolean; isSignalConnection: boolean; pendingAvatarDownload?: boolean; startAvatarDownload?: (id: string) => unknown; toggleSignalConnectionsModal: () => void; toggleSafetyNumberModal: (id: string) => void; toggleProfileNameWarningModal: () => void; updateSharedGroups: (id: string) => void; }>; export function AboutContactModal({ i18n, conversation, fromOrAddedByTrustedContact, isSignalConnection, pendingAvatarDownload, startAvatarDownload, toggleSignalConnectionsModal, toggleSafetyNumberModal, toggleProfileNameWarningModal, updateSharedGroups, onClose, onOpenNotePreviewModal, }: PropsType): JSX.Element { const { avatarUrl, hasAvatar, isMe } = conversation; useEffect(() => { // Kick off the expensive hydration of the current sharedGroupNames updateSharedGroups(conversation.id); }, [conversation.id, updateSharedGroups]); // If hasAvatar is true, we show the download button instead of blur const enableClickToLoad = !avatarUrl && !isMe && hasAvatar; const avatarBlur = enableClickToLoad ? AvatarBlur.BlurPictureWithClickToView : AvatarBlur.NoBlur; const avatarOnClick = useMemo(() => { if (!enableClickToLoad) { return undefined; } return () => { if (!pendingAvatarDownload && startAvatarDownload) { startAvatarDownload(conversation.id); } }; }, [ conversation.id, startAvatarDownload, enableClickToLoad, pendingAvatarDownload, ]); const onSignalConnectionClick = useCallback( (ev: React.MouseEvent) => { ev.preventDefault(); toggleSignalConnectionsModal(); }, [toggleSignalConnectionsModal] ); const onVerifiedClick = useCallback( (ev: React.MouseEvent) => { ev.preventDefault(); toggleSafetyNumberModal(conversation.id); }, [toggleSafetyNumberModal, conversation.id] ); const onProfileNameWarningClick = useCallback( (ev: React.MouseEvent) => { ev.preventDefault(); toggleProfileNameWarningModal(); }, [toggleProfileNameWarningModal] ); let statusRow: JSX.Element | undefined; if (isMe) { // No status for ourselves } else if (conversation.isBlocked) { statusRow = (
{i18n('icu:AboutContactModal__blocked', { name: conversation.title, })}
); } else if (!conversation.acceptedMessageRequest) { statusRow = (
{i18n('icu:AboutContactModal__message-request')}
); } else if (!conversation.hasMessages && !conversation.profileSharing) { statusRow = (
{i18n('icu:AboutContactModal__no-dms', { name: conversation.title, })}
); } return (

{isMe ? i18n('icu:AboutContactModal__title--myself') : i18n('icu:AboutContactModal__title')}

{canHaveNicknameAndNote(conversation) && (conversation.nicknameGivenName || conversation.nicknameFamilyName) && conversation.titleNoNickname ? ( , titleNoNickname: ( ), }} /> } delay={0} > ), muted, }} /> ) : ( )}
{!isMe && !fromOrAddedByTrustedContact ? (
) : null} {!isMe && conversation.isVerified ? (
) : null} {!isMe && conversation.about ? (
) : null} {!isMe && isSignalConnection ? (
) : null} {!isMe && isInSystemContacts(conversation) ? (
{i18n('icu:AboutContactModal__system-contact', { name: conversation.systemGivenName || conversation.firstName || conversation.title, })}
) : null} {conversation.phoneNumber ? (
) : null} {!isMe && (
)} {conversation.note && (
)} {statusRow}
); }