TelegramPWA/src/components/common/FullNameTitle.tsx
2026-03-05 12:43:25 +01:00

195 lines
6.1 KiB
TypeScript

import { memo, useMemo } from '../../lib/teact/teact';
import { getActions } from '../../global';
import type {
ApiPeer,
} from '../../api/types';
import type { ObserveFn } from '../../hooks/useIntersectionObserver';
import type { CustomPeer } from '../../types';
import { EMOJI_STATUS_LOOP_LIMIT } from '../../config';
import {
getChatTitle,
getUserFullName,
isAnonymousForwardsChat,
isChatWithRepliesBot,
isChatWithVerificationCodesBot,
} from '../../global/helpers';
import { isApiPeerUser } from '../../global/helpers/peers';
import buildClassName from '../../util/buildClassName';
import buildStyle from '../../util/buildStyle';
import { copyTextToClipboard } from '../../util/clipboard';
import stopEvent from '../../util/stopEvent';
import renderText from './helpers/renderText';
import useLang from '../../hooks/useLang';
import useLastCallback from '../../hooks/useLastCallback';
import useOldLang from '../../hooks/useOldLang';
import Transition from '../ui/Transition';
import CustomEmoji from './CustomEmoji';
import FakeIcon from './FakeIcon';
import GiftEffectWrapper from './gift/GiftEffectWrapper';
import StarIcon from './icons/StarIcon';
import VerifiedIcon from './VerifiedIcon';
import styles from './FullNameTitle.module.scss';
type OwnProps = {
peer: ApiPeer | CustomPeer;
className?: string;
style?: string;
noVerified?: boolean;
noFake?: boolean;
withEmojiStatus?: boolean;
emojiStatusSize?: number;
isSavedMessages?: boolean;
isSavedDialog?: boolean;
isMonoforum?: boolean;
monoforumBadgeClassName?: string;
noLoopLimit?: boolean;
canCopyTitle?: boolean;
iconElement?: React.ReactNode;
withStatusTextColor?: boolean;
onEmojiStatusClick?: NoneToVoidFunction;
observeIntersection?: ObserveFn;
};
const FullNameTitle = ({
className,
style,
peer,
noVerified,
noFake,
withEmojiStatus,
emojiStatusSize,
isSavedMessages,
isSavedDialog,
noLoopLimit,
canCopyTitle,
iconElement,
isMonoforum,
monoforumBadgeClassName,
withStatusTextColor,
onEmojiStatusClick,
observeIntersection,
}: OwnProps) => {
const { showNotification } = getActions();
const oldLang = useOldLang();
const lang = useLang();
const realPeer = 'id' in peer ? peer : undefined;
const customPeer = 'isCustomPeer' in peer ? peer : undefined;
const isUser = realPeer && isApiPeerUser(realPeer);
const title = realPeer && (isUser ? getUserFullName(realPeer) : getChatTitle(oldLang, realPeer));
const isPremium = (isUser && realPeer.isPremium) || customPeer?.isPremium;
const canShowEmojiStatus = withEmojiStatus && !isSavedMessages;
const emojiStatus = realPeer?.emojiStatus
|| (customPeer?.emojiStatusId ? { type: 'regular', documentId: customPeer.emojiStatusId } : undefined);
const handleTitleClick = useLastCallback((e) => {
if (!title || !canCopyTitle) {
return;
}
stopEvent(e);
copyTextToClipboard(title);
showNotification({ message: `${isUser ? 'User' : 'Chat'} name was copied` });
});
const specialTitle = useMemo(() => {
if (customPeer) {
return renderText(customPeer.title || oldLang(customPeer.titleKey!));
}
if (isSavedMessages) {
return oldLang(isSavedDialog ? 'MyNotes' : 'SavedMessages');
}
if (isAnonymousForwardsChat(realPeer!.id)) {
return oldLang('AnonymousForward');
}
if (isChatWithRepliesBot(realPeer!.id)) {
return oldLang('RepliesTitle');
}
if (isChatWithVerificationCodesBot(realPeer!.id)) {
return oldLang('VerifyCodesNotifications');
}
return undefined;
}, [customPeer, isSavedDialog, isSavedMessages, oldLang, realPeer]);
const botVerificationIconId = realPeer?.botVerificationIconId;
return (
<div
className={buildClassName('title', styles.root, className)}
style={buildStyle(emojiStatusSize ? `--_status-size: ${emojiStatusSize}px` : undefined, style)}
>
{botVerificationIconId && (
<CustomEmoji
documentId={botVerificationIconId}
size={emojiStatusSize}
loopLimit={!noLoopLimit ? EMOJI_STATUS_LOOP_LIMIT : undefined}
observeIntersectionForLoading={observeIntersection}
/>
)}
<h3
dir="auto"
role="button"
className={buildClassName(
'fullName',
styles.fullName,
canCopyTitle && styles.canCopy,
)}
onClick={handleTitleClick}
>
{specialTitle || renderText(title || '')}
</h3>
{!iconElement && peer && (
<>
{!noVerified && peer?.isVerified && <VerifiedIcon />}
{!noFake && peer?.fakeType && <FakeIcon fakeType={peer.fakeType} />}
{canShowEmojiStatus && emojiStatus && (
<Transition
className={styles.statusTransition}
slideClassName={styles.statusTransitionSlide}
activeKey={Number(emojiStatus.documentId)}
name="slideFade"
direction={-1}
shouldCleanup
>
<GiftEffectWrapper
withSparkles={emojiStatus.type === 'collectible'}
sparklesClassName="statusSparkles"
sparklesColor={emojiStatus.type === 'collectible' && !withStatusTextColor
? emojiStatus.textColor : undefined}
>
<CustomEmoji
className={buildClassName('no-selection', !withStatusTextColor && styles.statusPrimaryColor)}
documentId={emojiStatus.documentId}
size={emojiStatusSize}
loopLimit={!noLoopLimit ? EMOJI_STATUS_LOOP_LIMIT : undefined}
observeIntersectionForLoading={observeIntersection}
onClick={onEmojiStatusClick}
/>
</GiftEffectWrapper>
</Transition>
)}
{canShowEmojiStatus && !emojiStatus && isPremium && <StarIcon />}
{isMonoforum && (
<div className={buildClassName(styles.monoforumBadge, monoforumBadgeClassName)}>
{lang('MonoforumBadge')}
</div>
)}
</>
)}
{iconElement}
</div>
);
};
export default memo(FullNameTitle);