183 lines
4.9 KiB
TypeScript
183 lines
4.9 KiB
TypeScript
import { MouseEvent as ReactMouseEvent } from 'react';
|
|
import React, {
|
|
FC, useEffect, useCallback, memo,
|
|
} from '../../lib/teact/teact';
|
|
import { getDispatch, withGlobal } from '../../lib/teact/teactn';
|
|
|
|
import { ApiChat, ApiTypingStatus } from '../../api/types';
|
|
import { GlobalState } from '../../global/types';
|
|
import { MediaViewerOrigin } from '../../types';
|
|
|
|
import {
|
|
getChatTypeString,
|
|
getChatTitle,
|
|
isChatSuperGroup,
|
|
} from '../../modules/helpers';
|
|
import { selectChat, selectChatMessages, selectChatOnlineCount } from '../../modules/selectors';
|
|
import renderText from './helpers/renderText';
|
|
import useLang, { LangFn } from '../../hooks/useLang';
|
|
|
|
import Avatar from './Avatar';
|
|
import VerifiedIcon from './VerifiedIcon';
|
|
import TypingStatus from './TypingStatus';
|
|
import DotAnimation from './DotAnimation';
|
|
|
|
type OwnProps = {
|
|
chatId: string;
|
|
typingStatus?: ApiTypingStatus;
|
|
avatarSize?: 'small' | 'medium' | 'large' | 'jumbo';
|
|
status?: string;
|
|
withDots?: boolean;
|
|
withMediaViewer?: boolean;
|
|
withUsername?: boolean;
|
|
withFullInfo?: boolean;
|
|
withUpdatingStatus?: boolean;
|
|
withChatType?: boolean;
|
|
noRtl?: boolean;
|
|
};
|
|
|
|
type StateProps =
|
|
{
|
|
chat?: ApiChat;
|
|
onlineCount?: number;
|
|
areMessagesLoaded: boolean;
|
|
}
|
|
& Pick<GlobalState, 'lastSyncTime'>;
|
|
|
|
const GroupChatInfo: FC<OwnProps & StateProps> = ({
|
|
typingStatus,
|
|
avatarSize = 'medium',
|
|
status,
|
|
withDots,
|
|
withMediaViewer,
|
|
withUsername,
|
|
withFullInfo,
|
|
withUpdatingStatus,
|
|
withChatType,
|
|
noRtl,
|
|
chat,
|
|
onlineCount,
|
|
areMessagesLoaded,
|
|
lastSyncTime,
|
|
}) => {
|
|
const {
|
|
loadFullChat,
|
|
openMediaViewer,
|
|
} = getDispatch();
|
|
|
|
const isSuperGroup = chat && isChatSuperGroup(chat);
|
|
const { id: chatId, isMin, isRestricted } = chat || {};
|
|
|
|
useEffect(() => {
|
|
if (chatId && !isMin && withFullInfo && lastSyncTime) {
|
|
loadFullChat({ chatId });
|
|
}
|
|
}, [chatId, isMin, lastSyncTime, withFullInfo, loadFullChat, isSuperGroup]);
|
|
|
|
const handleAvatarViewerOpen = useCallback((e: ReactMouseEvent<HTMLDivElement, MouseEvent>, hasPhoto: boolean) => {
|
|
if (chat && hasPhoto) {
|
|
e.stopPropagation();
|
|
openMediaViewer({
|
|
avatarOwnerId: chat.id,
|
|
origin: avatarSize === 'jumbo' ? MediaViewerOrigin.ProfileAvatar : MediaViewerOrigin.MiddleHeaderAvatar,
|
|
});
|
|
}
|
|
}, [chat, avatarSize, openMediaViewer]);
|
|
|
|
const lang = useLang();
|
|
|
|
if (!chat) {
|
|
return undefined;
|
|
}
|
|
|
|
function renderStatusOrTyping() {
|
|
if (status) {
|
|
return withDots ? (
|
|
<DotAnimation className="status" content={status} />
|
|
) : (
|
|
<span className="status" dir="auto">{status}</span>
|
|
);
|
|
}
|
|
|
|
if (withUpdatingStatus && !areMessagesLoaded && !isRestricted) {
|
|
return (
|
|
<DotAnimation className="status" content={lang('Updating')} />
|
|
);
|
|
}
|
|
|
|
if (!chat) {
|
|
return undefined;
|
|
}
|
|
|
|
if (typingStatus) {
|
|
return <TypingStatus typingStatus={typingStatus} />;
|
|
}
|
|
|
|
if (withChatType) {
|
|
return (
|
|
<span className="status" dir="auto">{lang(getChatTypeString(chat))}</span>
|
|
);
|
|
}
|
|
|
|
const handle = withUsername ? chat.username : undefined;
|
|
const groupStatus = getGroupStatus(lang, chat);
|
|
const onlineStatus = onlineCount ? `, ${lang('OnlineCount', onlineCount, 'i')}` : undefined;
|
|
|
|
return (
|
|
<span className="status">
|
|
{handle && <span className="handle">{handle}</span>}
|
|
<span className="group-status">{groupStatus}</span>
|
|
{onlineStatus && <span className="online-status">{onlineStatus}</span>}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="ChatInfo" dir={!noRtl && lang.isRtl ? 'rtl' : undefined}>
|
|
<Avatar
|
|
key={chat.id}
|
|
size={avatarSize}
|
|
chat={chat}
|
|
onClick={withMediaViewer ? handleAvatarViewerOpen : undefined}
|
|
/>
|
|
<div className="info">
|
|
<div className="title">
|
|
<h3 dir="auto">{renderText(getChatTitle(lang, chat))}</h3>
|
|
{chat.isVerified && <VerifiedIcon />}
|
|
</div>
|
|
{renderStatusOrTyping()}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
function getGroupStatus(lang: LangFn, chat: ApiChat) {
|
|
const chatTypeString = lang(getChatTypeString(chat));
|
|
const { membersCount } = chat;
|
|
|
|
if (chat.isRestricted) {
|
|
return chatTypeString === 'Channel' ? 'channel is inaccessible' : 'group is inaccessible';
|
|
}
|
|
|
|
if (!membersCount) {
|
|
return chatTypeString;
|
|
}
|
|
|
|
return chatTypeString === 'Channel'
|
|
? lang('Subscribers', membersCount, 'i')
|
|
: lang('Members', membersCount, 'i');
|
|
}
|
|
|
|
export default memo(withGlobal<OwnProps>(
|
|
(global, { chatId }): StateProps => {
|
|
const { lastSyncTime } = global;
|
|
const chat = selectChat(global, chatId);
|
|
const onlineCount = chat ? selectChatOnlineCount(global, chat) : undefined;
|
|
const areMessagesLoaded = Boolean(selectChatMessages(global, chatId));
|
|
|
|
return {
|
|
lastSyncTime, chat, onlineCount, areMessagesLoaded,
|
|
};
|
|
},
|
|
)(GroupChatInfo));
|