273 lines
8.8 KiB
TypeScript
273 lines
8.8 KiB
TypeScript
// Copyright 2024 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
import React, { useCallback, useEffect } from 'react';
|
|
import type { ConversationType } from '../../state/ducks/conversations';
|
|
import type { LocalizerType } from '../../types/Util';
|
|
import { isInSystemContacts } from '../../util/isInSystemContacts';
|
|
import { shouldBlurAvatar } from '../../util/shouldBlurAvatar';
|
|
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<string | JSX.Element>) {
|
|
return (
|
|
<span className="AboutContactModal__TitleWithoutNickname">{parts}</span>
|
|
);
|
|
}
|
|
|
|
export type PropsType = Readonly<{
|
|
i18n: LocalizerType;
|
|
onClose: () => void;
|
|
onOpenNotePreviewModal: () => void;
|
|
conversation: ConversationType;
|
|
isSignalConnection: boolean;
|
|
toggleSignalConnectionsModal: () => void;
|
|
toggleSafetyNumberModal: (id: string) => void;
|
|
updateSharedGroups: (id: string) => void;
|
|
unblurAvatar: (conversationId: string) => void;
|
|
}>;
|
|
|
|
export function AboutContactModal({
|
|
i18n,
|
|
conversation,
|
|
isSignalConnection,
|
|
toggleSignalConnectionsModal,
|
|
toggleSafetyNumberModal,
|
|
updateSharedGroups,
|
|
unblurAvatar,
|
|
onClose,
|
|
onOpenNotePreviewModal,
|
|
}: PropsType): JSX.Element {
|
|
const { isMe } = conversation;
|
|
|
|
useEffect(() => {
|
|
// Kick off the expensive hydration of the current sharedGroupNames
|
|
updateSharedGroups(conversation.id);
|
|
}, [conversation.id, updateSharedGroups]);
|
|
|
|
const avatarBlur = shouldBlurAvatar(conversation)
|
|
? AvatarBlur.BlurPictureWithClickToView
|
|
: AvatarBlur.NoBlur;
|
|
|
|
const onAvatarClick = useCallback(() => {
|
|
if (avatarBlur === AvatarBlur.BlurPictureWithClickToView) {
|
|
unblurAvatar(conversation.id);
|
|
}
|
|
}, [avatarBlur, unblurAvatar, conversation.id]);
|
|
|
|
const onSignalConnectionClick = useCallback(
|
|
(ev: React.MouseEvent) => {
|
|
ev.preventDefault();
|
|
toggleSignalConnectionsModal();
|
|
},
|
|
[toggleSignalConnectionsModal]
|
|
);
|
|
|
|
const onVerifiedClick = useCallback(
|
|
(ev: React.MouseEvent) => {
|
|
ev.preventDefault();
|
|
toggleSafetyNumberModal(conversation.id);
|
|
},
|
|
[toggleSafetyNumberModal, conversation.id]
|
|
);
|
|
|
|
let statusRow: JSX.Element | undefined;
|
|
|
|
if (isMe) {
|
|
// No status for ourselves
|
|
} else if (conversation.isBlocked) {
|
|
statusRow = (
|
|
<div className="AboutContactModal__row">
|
|
<i className="AboutContactModal__row__icon AboutContactModal__row__icon--blocked" />
|
|
{i18n('icu:AboutContactModal__blocked', {
|
|
name: conversation.title,
|
|
})}
|
|
</div>
|
|
);
|
|
} else if (!conversation.acceptedMessageRequest) {
|
|
statusRow = (
|
|
<div className="AboutContactModal__row">
|
|
<i className="AboutContactModal__row__icon AboutContactModal__row__icon--message-request" />
|
|
{i18n('icu:AboutContactModal__message-request')}
|
|
</div>
|
|
);
|
|
} else if (!conversation.hasMessages && !conversation.profileSharing) {
|
|
statusRow = (
|
|
<div className="AboutContactModal__row">
|
|
<i className="AboutContactModal__row__icon AboutContactModal__row__icon--no-dms" />
|
|
{i18n('icu:AboutContactModal__no-dms', {
|
|
name: conversation.title,
|
|
})}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Modal
|
|
key="main"
|
|
modalName="AboutContactModal"
|
|
moduleClassName="AboutContactModal"
|
|
hasXButton
|
|
i18n={i18n}
|
|
onClose={onClose}
|
|
>
|
|
<div className="AboutContactModal__row AboutContactModal__row--centered">
|
|
<Avatar
|
|
acceptedMessageRequest={conversation.acceptedMessageRequest}
|
|
avatarUrl={conversation.avatarUrl}
|
|
blur={avatarBlur}
|
|
onClick={avatarBlur === AvatarBlur.NoBlur ? undefined : onAvatarClick}
|
|
badge={undefined}
|
|
color={conversation.color}
|
|
conversationType="direct"
|
|
i18n={i18n}
|
|
isMe={conversation.isMe}
|
|
profileName={conversation.profileName}
|
|
sharedGroupNames={[]}
|
|
size={AvatarSize.TWO_HUNDRED_SIXTEEN}
|
|
title={conversation.title}
|
|
unblurredAvatarUrl={conversation.unblurredAvatarUrl}
|
|
/>
|
|
</div>
|
|
|
|
<div className="AboutContactModal__row">
|
|
<h3 className="AboutContactModal__title">
|
|
{isMe
|
|
? i18n('icu:AboutContactModal__title--myself')
|
|
: i18n('icu:AboutContactModal__title')}
|
|
</h3>
|
|
</div>
|
|
|
|
<div className="AboutContactModal__row">
|
|
<i className="AboutContactModal__row__icon AboutContactModal__row__icon--profile" />
|
|
|
|
{canHaveNicknameAndNote(conversation) &&
|
|
(conversation.nicknameGivenName || conversation.nicknameFamilyName) &&
|
|
conversation.titleNoNickname ? (
|
|
<span>
|
|
<I18n
|
|
i18n={i18n}
|
|
id="icu:AboutContactModal__TitleAndTitleWithoutNickname"
|
|
components={{
|
|
nickname: <UserText text={conversation.title} />,
|
|
titleNoNickname: (
|
|
<Tooltip
|
|
className="AboutContactModal__TitleWithoutNickname__Tooltip"
|
|
direction={TooltipPlacement.Top}
|
|
content={
|
|
<I18n
|
|
i18n={i18n}
|
|
id="icu:AboutContactModal__TitleWithoutNickname__Tooltip"
|
|
components={{
|
|
title: (
|
|
<UserText text={conversation.titleNoNickname} />
|
|
),
|
|
}}
|
|
/>
|
|
}
|
|
delay={0}
|
|
>
|
|
<UserText text={conversation.titleNoNickname} />
|
|
</Tooltip>
|
|
),
|
|
muted,
|
|
}}
|
|
/>
|
|
</span>
|
|
) : (
|
|
<UserText text={conversation.title} />
|
|
)}
|
|
</div>
|
|
|
|
{!isMe && conversation.isVerified ? (
|
|
<div className="AboutContactModal__row">
|
|
<i className="AboutContactModal__row__icon AboutContactModal__row__icon--verified" />
|
|
<button
|
|
type="button"
|
|
className="AboutContactModal__verified"
|
|
onClick={onVerifiedClick}
|
|
>
|
|
{i18n('icu:AboutContactModal__verified')}
|
|
</button>
|
|
</div>
|
|
) : null}
|
|
|
|
{!isMe && conversation.about ? (
|
|
<div className="AboutContactModal__row">
|
|
<i className="AboutContactModal__row__icon AboutContactModal__row__icon--about" />
|
|
<About
|
|
className="AboutContactModal__about"
|
|
text={conversation.about}
|
|
/>
|
|
</div>
|
|
) : null}
|
|
|
|
{!isMe && isSignalConnection ? (
|
|
<div className="AboutContactModal__row">
|
|
<i className="AboutContactModal__row__icon AboutContactModal__row__icon--connections" />
|
|
<button
|
|
type="button"
|
|
className="AboutContactModal__button"
|
|
onClick={onSignalConnectionClick}
|
|
>
|
|
{i18n('icu:AboutContactModal__signal-connection')}
|
|
</button>
|
|
</div>
|
|
) : null}
|
|
|
|
{!isMe && isInSystemContacts(conversation) ? (
|
|
<div className="AboutContactModal__row">
|
|
<i className="AboutContactModal__row__icon AboutContactModal__row__icon--person" />
|
|
{i18n('icu:AboutContactModal__system-contact', {
|
|
name:
|
|
conversation.systemGivenName ||
|
|
conversation.firstName ||
|
|
conversation.title,
|
|
})}
|
|
</div>
|
|
) : null}
|
|
|
|
{conversation.phoneNumber ? (
|
|
<div className="AboutContactModal__row">
|
|
<i className="AboutContactModal__row__icon AboutContactModal__row__icon--phone" />
|
|
<UserText text={conversation.phoneNumber} />
|
|
</div>
|
|
) : null}
|
|
|
|
{!isMe && (
|
|
<div className="AboutContactModal__row">
|
|
<i className="AboutContactModal__row__icon AboutContactModal__row__icon--group" />
|
|
<div>
|
|
<SharedGroupNames
|
|
i18n={i18n}
|
|
sharedGroupNames={conversation.sharedGroupNames || []}
|
|
/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{conversation.note && (
|
|
<div className="AboutContactModal__row">
|
|
<i className="AboutContactModal__row__icon AboutContactModal__row__icon--note" />
|
|
<button
|
|
type="button"
|
|
className="AboutContactModal__button"
|
|
onClick={onOpenNotePreviewModal}
|
|
>
|
|
<div className="AboutContactModal__OneLineEllipsis">
|
|
<UserText text={conversation.note} />
|
|
</div>
|
|
</button>
|
|
</div>
|
|
)}
|
|
|
|
{statusRow}
|
|
</Modal>
|
|
);
|
|
}
|