2021-04-30 19:40:25 +00:00
|
|
|
// Copyright 2020-2021 Signal Messenger, LLC
|
2020-10-30 20:34:04 +00:00
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
2021-04-30 22:58:57 +00:00
|
|
|
import React, { useEffect, useRef, useState } from 'react';
|
2021-10-26 19:15:33 +00:00
|
|
|
import type { Props as AvatarProps } from '../Avatar';
|
|
|
|
import { Avatar, AvatarBlur } from '../Avatar';
|
2020-05-27 21:37:06 +00:00
|
|
|
import { ContactName } from './ContactName';
|
2021-01-26 01:01:19 +00:00
|
|
|
import { About } from './About';
|
2021-06-02 00:24:28 +00:00
|
|
|
import { GroupDescription } from './GroupDescription';
|
2021-04-16 15:51:26 +00:00
|
|
|
import { SharedGroupNames } from '../SharedGroupNames';
|
2021-10-26 19:15:33 +00:00
|
|
|
import type { LocalizerType } from '../../types/Util';
|
2021-04-30 22:58:57 +00:00
|
|
|
import { ConfirmationDialog } from '../ConfirmationDialog';
|
|
|
|
import { Button, ButtonSize, ButtonVariant } from '../Button';
|
2021-04-30 19:40:25 +00:00
|
|
|
import { shouldBlurAvatar } from '../../util/shouldBlurAvatar';
|
2021-09-17 18:27:53 +00:00
|
|
|
import * as log from '../../logging/log';
|
2021-09-21 20:45:25 +00:00
|
|
|
import { openLinkInWebBrowser } from '../../util/openLinkInWebBrowser';
|
2020-05-27 21:37:06 +00:00
|
|
|
|
|
|
|
export type Props = {
|
2021-01-26 01:01:19 +00:00
|
|
|
about?: string;
|
2021-04-30 19:40:25 +00:00
|
|
|
acceptedMessageRequest?: boolean;
|
2021-06-02 00:24:28 +00:00
|
|
|
groupDescription?: string;
|
2020-05-27 21:37:06 +00:00
|
|
|
i18n: LocalizerType;
|
2021-05-07 22:21:10 +00:00
|
|
|
isMe: boolean;
|
2020-05-27 21:37:06 +00:00
|
|
|
membersCount?: number;
|
2021-09-16 21:44:00 +00:00
|
|
|
onHeightChange: () => unknown;
|
2021-04-30 22:58:57 +00:00
|
|
|
phoneNumber?: string;
|
|
|
|
sharedGroupNames?: Array<string>;
|
2021-04-30 19:40:25 +00:00
|
|
|
unblurAvatar: () => void;
|
|
|
|
unblurredAvatarPath?: string;
|
2021-04-30 22:58:57 +00:00
|
|
|
updateSharedGroups: () => unknown;
|
2020-05-27 21:37:06 +00:00
|
|
|
} & Omit<AvatarProps, 'onClick' | 'size' | 'noteToSelf'>;
|
|
|
|
|
|
|
|
const renderMembershipRow = ({
|
2021-04-30 22:58:57 +00:00
|
|
|
acceptedMessageRequest,
|
2020-05-27 21:37:06 +00:00
|
|
|
conversationType,
|
2021-04-30 22:58:57 +00:00
|
|
|
i18n,
|
2020-05-27 21:37:06 +00:00
|
|
|
isMe,
|
2021-04-30 22:58:57 +00:00
|
|
|
onClickMessageRequestWarning,
|
|
|
|
phoneNumber,
|
|
|
|
sharedGroupNames,
|
2021-04-01 16:27:17 +00:00
|
|
|
}: Pick<
|
|
|
|
Props,
|
2021-04-30 22:58:57 +00:00
|
|
|
| 'acceptedMessageRequest'
|
|
|
|
| 'conversationType'
|
|
|
|
| 'i18n'
|
|
|
|
| 'isMe'
|
|
|
|
| 'phoneNumber'
|
|
|
|
> &
|
|
|
|
Required<Pick<Props, 'sharedGroupNames'>> & {
|
|
|
|
onClickMessageRequestWarning: () => void;
|
|
|
|
}) => {
|
2020-05-27 21:37:06 +00:00
|
|
|
const className = 'module-conversation-hero__membership';
|
|
|
|
|
2021-04-01 16:27:17 +00:00
|
|
|
if (conversationType !== 'direct') {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2020-05-27 21:37:06 +00:00
|
|
|
if (isMe) {
|
|
|
|
return <div className={className}>{i18n('noteToSelfHero')}</div>;
|
|
|
|
}
|
|
|
|
|
2021-04-01 16:27:17 +00:00
|
|
|
if (sharedGroupNames.length > 0) {
|
2021-04-16 15:51:26 +00:00
|
|
|
return (
|
|
|
|
<div className={className}>
|
|
|
|
<SharedGroupNames
|
|
|
|
i18n={i18n}
|
|
|
|
nameClassName={`${className}__name`}
|
|
|
|
sharedGroupNames={sharedGroupNames}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
);
|
2020-05-27 21:37:06 +00:00
|
|
|
}
|
2021-04-30 22:58:57 +00:00
|
|
|
if (acceptedMessageRequest) {
|
|
|
|
if (phoneNumber) {
|
|
|
|
return null;
|
|
|
|
}
|
2021-04-01 16:27:17 +00:00
|
|
|
return <div className={className}>{i18n('no-groups-in-common')}</div>;
|
|
|
|
}
|
|
|
|
|
2021-04-30 22:58:57 +00:00
|
|
|
return (
|
|
|
|
<div className="module-conversation-hero__message-request-warning">
|
|
|
|
<div className="module-conversation-hero__message-request-warning__message">
|
|
|
|
{i18n('no-groups-in-common-warning')}
|
|
|
|
</div>
|
|
|
|
<Button
|
|
|
|
onClick={onClickMessageRequestWarning}
|
|
|
|
size={ButtonSize.Small}
|
|
|
|
variant={ButtonVariant.SecondaryAffirmative}
|
|
|
|
>
|
|
|
|
{i18n('MessageRequestWarning__learn-more')}
|
|
|
|
</Button>
|
|
|
|
</div>
|
|
|
|
);
|
2020-05-27 21:37:06 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
export const ConversationHero = ({
|
|
|
|
i18n,
|
2021-01-26 01:01:19 +00:00
|
|
|
about,
|
2021-04-30 19:40:25 +00:00
|
|
|
acceptedMessageRequest,
|
2020-05-27 21:37:06 +00:00
|
|
|
avatarPath,
|
|
|
|
color,
|
|
|
|
conversationType,
|
2021-06-02 00:24:28 +00:00
|
|
|
groupDescription,
|
2020-05-27 21:37:06 +00:00
|
|
|
isMe,
|
|
|
|
membersCount,
|
2020-08-05 01:13:19 +00:00
|
|
|
sharedGroupNames = [],
|
2020-05-27 21:37:06 +00:00
|
|
|
name,
|
|
|
|
phoneNumber,
|
|
|
|
profileName,
|
2020-07-24 01:35:32 +00:00
|
|
|
title,
|
2020-05-27 21:37:06 +00:00
|
|
|
onHeightChange,
|
2021-04-30 19:40:25 +00:00
|
|
|
unblurAvatar,
|
|
|
|
unblurredAvatarPath,
|
2020-08-07 00:50:54 +00:00
|
|
|
updateSharedGroups,
|
2020-09-14 19:51:27 +00:00
|
|
|
}: Props): JSX.Element => {
|
2021-04-30 22:58:57 +00:00
|
|
|
const firstRenderRef = useRef(true);
|
2020-05-27 21:37:06 +00:00
|
|
|
|
2021-04-30 22:58:57 +00:00
|
|
|
const [
|
|
|
|
isShowingMessageRequestWarning,
|
|
|
|
setIsShowingMessageRequestWarning,
|
|
|
|
] = useState(false);
|
|
|
|
const closeMessageRequestWarning = () => {
|
|
|
|
setIsShowingMessageRequestWarning(false);
|
|
|
|
};
|
2020-08-07 00:50:54 +00:00
|
|
|
|
2021-04-30 22:58:57 +00:00
|
|
|
useEffect(() => {
|
|
|
|
// Kick off the expensive hydration of the current sharedGroupNames
|
|
|
|
updateSharedGroups();
|
|
|
|
}, [updateSharedGroups]);
|
|
|
|
|
2021-08-19 16:36:09 +00:00
|
|
|
const sharedGroupNamesStringified = JSON.stringify(sharedGroupNames);
|
2021-04-30 22:58:57 +00:00
|
|
|
useEffect(() => {
|
2021-08-19 16:36:09 +00:00
|
|
|
const isFirstRender = firstRenderRef.current;
|
|
|
|
if (isFirstRender) {
|
|
|
|
firstRenderRef.current = false;
|
|
|
|
return;
|
2021-04-30 22:58:57 +00:00
|
|
|
}
|
2020-05-27 21:37:06 +00:00
|
|
|
|
2021-09-17 18:27:53 +00:00
|
|
|
log.info('ConversationHero: calling onHeightChange');
|
2021-09-16 21:44:00 +00:00
|
|
|
onHeightChange();
|
2021-08-19 16:36:09 +00:00
|
|
|
}, [
|
|
|
|
about,
|
|
|
|
conversationType,
|
|
|
|
groupDescription,
|
|
|
|
isMe,
|
|
|
|
membersCount,
|
|
|
|
name,
|
|
|
|
onHeightChange,
|
|
|
|
phoneNumber,
|
|
|
|
profileName,
|
|
|
|
title,
|
|
|
|
sharedGroupNamesStringified,
|
|
|
|
]);
|
2021-05-05 22:35:32 +00:00
|
|
|
|
2021-04-30 19:40:25 +00:00
|
|
|
let avatarBlur: AvatarBlur;
|
|
|
|
let avatarOnClick: undefined | (() => void);
|
|
|
|
if (
|
|
|
|
shouldBlurAvatar({
|
|
|
|
acceptedMessageRequest,
|
|
|
|
avatarPath,
|
|
|
|
isMe,
|
|
|
|
sharedGroupNames,
|
|
|
|
unblurredAvatarPath,
|
|
|
|
})
|
|
|
|
) {
|
|
|
|
avatarBlur = AvatarBlur.BlurPictureWithClickToView;
|
|
|
|
avatarOnClick = unblurAvatar;
|
|
|
|
} else {
|
|
|
|
avatarBlur = AvatarBlur.NoBlur;
|
|
|
|
}
|
|
|
|
|
2020-07-24 01:35:32 +00:00
|
|
|
const phoneNumberOnly = Boolean(
|
|
|
|
!name && !profileName && conversationType === 'direct'
|
|
|
|
);
|
|
|
|
|
2020-09-14 19:51:27 +00:00
|
|
|
/* eslint-disable no-nested-ternary */
|
2020-05-27 21:37:06 +00:00
|
|
|
return (
|
2021-04-30 22:58:57 +00:00
|
|
|
<>
|
2021-08-19 16:36:09 +00:00
|
|
|
<div className="module-conversation-hero">
|
|
|
|
<Avatar
|
|
|
|
acceptedMessageRequest={acceptedMessageRequest}
|
|
|
|
avatarPath={avatarPath}
|
|
|
|
blur={avatarBlur}
|
|
|
|
className="module-conversation-hero__avatar"
|
|
|
|
color={color}
|
|
|
|
conversationType={conversationType}
|
|
|
|
i18n={i18n}
|
|
|
|
isMe={isMe}
|
|
|
|
name={name}
|
|
|
|
noteToSelf={isMe}
|
|
|
|
onClick={avatarOnClick}
|
|
|
|
profileName={profileName}
|
|
|
|
sharedGroupNames={sharedGroupNames}
|
|
|
|
size={112}
|
|
|
|
title={title}
|
|
|
|
/>
|
|
|
|
<h1 className="module-conversation-hero__profile-name">
|
2021-09-16 16:15:43 +00:00
|
|
|
{isMe ? i18n('noteToSelf') : <ContactName title={title} />}
|
2021-08-19 16:36:09 +00:00
|
|
|
</h1>
|
|
|
|
{about && !isMe && (
|
|
|
|
<div className="module-about__container">
|
|
|
|
<About text={about} />
|
2021-04-30 22:58:57 +00:00
|
|
|
</div>
|
2020-05-27 21:37:06 +00:00
|
|
|
)}
|
2021-08-19 16:36:09 +00:00
|
|
|
{!isMe ? (
|
|
|
|
<div className="module-conversation-hero__with">
|
|
|
|
{groupDescription ? (
|
|
|
|
<GroupDescription
|
|
|
|
i18n={i18n}
|
|
|
|
title={title}
|
|
|
|
text={groupDescription}
|
|
|
|
/>
|
|
|
|
) : membersCount === 1 ? (
|
|
|
|
i18n('ConversationHero--members-1')
|
|
|
|
) : membersCount !== undefined ? (
|
|
|
|
i18n('ConversationHero--members', [`${membersCount}`])
|
|
|
|
) : phoneNumberOnly ? null : (
|
|
|
|
phoneNumber
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
) : null}
|
|
|
|
{renderMembershipRow({
|
|
|
|
acceptedMessageRequest,
|
|
|
|
conversationType,
|
|
|
|
i18n,
|
|
|
|
isMe,
|
|
|
|
onClickMessageRequestWarning() {
|
|
|
|
setIsShowingMessageRequestWarning(true);
|
|
|
|
},
|
|
|
|
phoneNumber,
|
|
|
|
sharedGroupNames,
|
|
|
|
})}
|
|
|
|
</div>
|
2021-04-30 22:58:57 +00:00
|
|
|
{isShowingMessageRequestWarning && (
|
|
|
|
<ConfirmationDialog
|
|
|
|
i18n={i18n}
|
|
|
|
onClose={closeMessageRequestWarning}
|
|
|
|
actions={[
|
|
|
|
{
|
|
|
|
text: i18n('MessageRequestWarning__dialog__learn-even-more'),
|
|
|
|
action: () => {
|
2021-09-21 20:45:25 +00:00
|
|
|
openLinkInWebBrowser(
|
|
|
|
'https://support.signal.org/hc/articles/360007459591'
|
|
|
|
);
|
2021-04-30 22:58:57 +00:00
|
|
|
closeMessageRequestWarning();
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]}
|
|
|
|
>
|
|
|
|
{i18n('MessageRequestWarning__dialog__details')}
|
|
|
|
</ConfirmationDialog>
|
2021-01-26 01:01:19 +00:00
|
|
|
)}
|
2021-04-30 22:58:57 +00:00
|
|
|
</>
|
2020-05-27 21:37:06 +00:00
|
|
|
);
|
2020-09-14 19:51:27 +00:00
|
|
|
/* eslint-enable no-nested-ternary */
|
2020-05-27 21:37:06 +00:00
|
|
|
};
|