Chat: Add mini app button (#5263)
This commit is contained in:
parent
7fd8062f1a
commit
81386ba911
@ -21,7 +21,6 @@ import { StoryViewerOrigin } from '../../../types';
|
||||
|
||||
import {
|
||||
getMessageAction,
|
||||
getPrivateChatUserId,
|
||||
groupStatetefulContent,
|
||||
isUserId,
|
||||
isUserOnline,
|
||||
@ -367,6 +366,7 @@ const Chat: FC<OwnProps & StateProps> = ({
|
||||
shouldShowOnlyMostImportant
|
||||
forceHidden={getIsForumPanelClosed}
|
||||
topics={topics}
|
||||
isSelected={isSelected}
|
||||
/>
|
||||
</div>
|
||||
{chat.isCallActive && chat.isCallNotEmpty && (
|
||||
@ -400,7 +400,9 @@ const Chat: FC<OwnProps & StateProps> = ({
|
||||
isPinned={isPinned}
|
||||
isMuted={isMuted}
|
||||
isSavedDialog={isSavedDialog}
|
||||
hasMiniApp={user?.hasMainMiniApp}
|
||||
topics={topics}
|
||||
isSelected={isSelected}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@ -439,6 +441,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
chatId, isSavedDialog, isPreview, previewMessageId,
|
||||
}): StateProps => {
|
||||
const chat = selectChat(global, chatId);
|
||||
const user = selectUser(global, chatId);
|
||||
if (!chat) {
|
||||
return {
|
||||
currentUserId: global.currentUserId!,
|
||||
@ -458,7 +461,6 @@ export default memo(withGlobal<OwnProps>(
|
||||
? selectChatMessage(global, chat.id, replyToMessageId)
|
||||
: undefined;
|
||||
const { targetUserIds: actionTargetUserIds, targetChatId: actionTargetChatId } = lastMessageAction || {};
|
||||
const privateChatUserId = getPrivateChatUserId(chat);
|
||||
|
||||
const {
|
||||
chatId: currentChatId,
|
||||
@ -470,8 +472,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
const isSelectedForum = (chat.isForum && chatId === currentChatId)
|
||||
|| chatId === selectTabState(global).forumPanelChatId;
|
||||
|
||||
const user = privateChatUserId ? selectUser(global, privateChatUserId) : undefined;
|
||||
const userStatus = privateChatUserId ? selectUserStatus(global, privateChatUserId) : undefined;
|
||||
const userStatus = selectUserStatus(global, chatId);
|
||||
const lastMessageTopic = lastMessage && selectTopicFromMessage(global, lastMessage);
|
||||
|
||||
const typingStatus = selectThreadParam(global, chatId, MAIN_THREAD_ID, 'typingStatus');
|
||||
|
||||
@ -97,4 +97,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.miniapp {
|
||||
z-index: calc(var(--z-chat-ripple) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import React, { memo, useMemo } from '../../../lib/teact/teact';
|
||||
import { getActions } from '../../../global';
|
||||
|
||||
import type { ApiChat, ApiTopic } from '../../../api/types';
|
||||
import type { Signal } from '../../../util/signals';
|
||||
@ -7,10 +8,14 @@ import type { Signal } from '../../../util/signals';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import { isSignal } from '../../../util/signals';
|
||||
import { formatIntegerCompact } from '../../../util/textFormat';
|
||||
import { extractCurrentThemeParams } from '../../../util/themeStyle';
|
||||
|
||||
import useDerivedState from '../../../hooks/useDerivedState';
|
||||
import useLastCallback from '../../../hooks/useLastCallback';
|
||||
import useOldLang from '../../../hooks/useOldLang';
|
||||
|
||||
import AnimatedCounter from '../../common/AnimatedCounter';
|
||||
import Button from '../../ui/Button';
|
||||
import ShowTransition from '../../ui/ShowTransition';
|
||||
|
||||
import './ChatBadge.scss';
|
||||
@ -23,8 +28,10 @@ type OwnProps = {
|
||||
isMuted?: boolean;
|
||||
isSavedDialog?: boolean;
|
||||
shouldShowOnlyMostImportant?: boolean;
|
||||
hasMiniApp?: boolean;
|
||||
forceHidden?: boolean | Signal<boolean>;
|
||||
topics?: Record<number, ApiTopic>;
|
||||
isSelected?: boolean;
|
||||
};
|
||||
|
||||
const ChatBadge: FC<OwnProps> = ({
|
||||
@ -37,7 +44,13 @@ const ChatBadge: FC<OwnProps> = ({
|
||||
wasTopicOpened,
|
||||
forceHidden,
|
||||
isSavedDialog,
|
||||
hasMiniApp,
|
||||
isSelected,
|
||||
}) => {
|
||||
const { requestMainWebView } = getActions();
|
||||
|
||||
const oldLang = useOldLang();
|
||||
|
||||
const {
|
||||
unreadMentionsCount = 0, unreadReactionsCount = 0,
|
||||
} = !chat.isForum ? chat : {}; // TODO[forums] Unread mentions and reactions temporarily disabled for forums
|
||||
@ -71,7 +84,7 @@ const ChatBadge: FC<OwnProps> = ({
|
||||
);
|
||||
const isShown = !resolvedForceHidden && Boolean(
|
||||
unreadCount || unreadMentionsCount || hasUnreadMark || isPinned || unreadReactionsCount
|
||||
|| isTopicUnopened,
|
||||
|| isTopicUnopened || hasMiniApp,
|
||||
);
|
||||
|
||||
const isUnread = Boolean((unreadCount || hasUnreadMark) && !isSavedDialog);
|
||||
@ -82,6 +95,18 @@ const ChatBadge: FC<OwnProps> = ({
|
||||
isUnread && 'unread',
|
||||
);
|
||||
|
||||
const handleOpenApp = useLastCallback((e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||
e.stopPropagation();
|
||||
|
||||
const theme = extractCurrentThemeParams();
|
||||
requestMainWebView({
|
||||
botId: chat.id,
|
||||
peerId: chat.id,
|
||||
theme,
|
||||
shouldMarkBotTrusted: true,
|
||||
});
|
||||
});
|
||||
|
||||
function renderContent() {
|
||||
const unreadReactionsElement = unreadReactionsCount && (
|
||||
<div className={buildClassName('ChatBadge reaction', shouldBeMuted && 'muted')}>
|
||||
@ -111,6 +136,18 @@ const ChatBadge: FC<OwnProps> = ({
|
||||
</div>
|
||||
);
|
||||
|
||||
const miniAppButton = hasMiniApp && (
|
||||
<Button
|
||||
color={isSelected ? 'secondary' : 'primary'}
|
||||
className="ChatBadge miniapp"
|
||||
pill
|
||||
size="tiny"
|
||||
onClick={handleOpenApp}
|
||||
>
|
||||
{oldLang('BotOpen')}
|
||||
</Button>
|
||||
);
|
||||
|
||||
const visiblePinnedElement = !unreadCountElement && !unreadMentionsElement && !unreadReactionsElement
|
||||
&& pinnedElement;
|
||||
|
||||
@ -120,6 +157,9 @@ const ChatBadge: FC<OwnProps> = ({
|
||||
|
||||
if (isSavedDialog) return pinnedElement;
|
||||
|
||||
// Show only if empty or have pinned icon
|
||||
if (hasMiniApp && (elements.length === 0 || visiblePinnedElement)) return miniAppButton;
|
||||
|
||||
if (elements.length === 0) return undefined;
|
||||
|
||||
if (elements.length === 1) return elements[0];
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import React, { memo, useCallback } from '../../../lib/teact/teact';
|
||||
import { withGlobal } from '../../../global';
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
import type { ApiChat, ApiUser } from '../../../api/types';
|
||||
import { StoryViewerOrigin } from '../../../types';
|
||||
@ -10,13 +10,17 @@ import {
|
||||
selectChat, selectIsChatPinned, selectNotifyExceptions,
|
||||
selectNotifySettings, selectUser,
|
||||
} from '../../../global/selectors';
|
||||
import { extractCurrentThemeParams } from '../../../util/themeStyle';
|
||||
|
||||
import useChatContextActions from '../../../hooks/useChatContextActions';
|
||||
import useFlag from '../../../hooks/useFlag';
|
||||
import useLastCallback from '../../../hooks/useLastCallback';
|
||||
import useOldLang from '../../../hooks/useOldLang';
|
||||
import useSelectWithEnter from '../../../hooks/useSelectWithEnter';
|
||||
|
||||
import GroupChatInfo from '../../common/GroupChatInfo';
|
||||
import PrivateChatInfo from '../../common/PrivateChatInfo';
|
||||
import Button from '../../ui/Button';
|
||||
import ListItem from '../../ui/ListItem';
|
||||
import ChatFolderModal from '../ChatFolderModal.async';
|
||||
import MuteChatModal from '../MuteChatModal.async';
|
||||
@ -24,6 +28,7 @@ import MuteChatModal from '../MuteChatModal.async';
|
||||
type OwnProps = {
|
||||
chatId: string;
|
||||
withUsername?: boolean;
|
||||
isRecent?: boolean;
|
||||
onClick: (id: string) => void;
|
||||
};
|
||||
|
||||
@ -38,13 +43,17 @@ type StateProps = {
|
||||
const LeftSearchResultChat: FC<OwnProps & StateProps> = ({
|
||||
chatId,
|
||||
withUsername,
|
||||
onClick,
|
||||
chat,
|
||||
user,
|
||||
isPinned,
|
||||
isMuted,
|
||||
canChangeFolder,
|
||||
isRecent,
|
||||
onClick,
|
||||
}) => {
|
||||
const { requestMainWebView } = getActions();
|
||||
const oldLang = useOldLang();
|
||||
|
||||
const [isMuteModalOpen, openMuteModal, closeMuteModal] = useFlag();
|
||||
const [isChatFolderModalOpen, openChatFolderModal, closeChatFolderModal] = useFlag();
|
||||
const [shouldRenderChatFolderModal, markRenderChatFolderModal, unmarkRenderChatFolderModal] = useFlag();
|
||||
@ -70,9 +79,21 @@ const LeftSearchResultChat: FC<OwnProps & StateProps> = ({
|
||||
handleChatFolderChange,
|
||||
}, true);
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
const handleClick = useLastCallback(() => {
|
||||
onClick(chatId);
|
||||
}, [chatId, onClick]);
|
||||
});
|
||||
|
||||
const handleOpenApp = useLastCallback((e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||
e.stopPropagation();
|
||||
|
||||
const theme = extractCurrentThemeParams();
|
||||
requestMainWebView({
|
||||
botId: chatId,
|
||||
peerId: chatId,
|
||||
theme,
|
||||
shouldMarkBotTrusted: true,
|
||||
});
|
||||
});
|
||||
|
||||
const buttonRef = useSelectWithEnter(handleClick);
|
||||
|
||||
@ -100,6 +121,17 @@ const LeftSearchResultChat: FC<OwnProps & StateProps> = ({
|
||||
storyViewerOrigin={StoryViewerOrigin.SearchResult}
|
||||
/>
|
||||
)}
|
||||
{isRecent && user?.hasMainMiniApp && (
|
||||
<Button
|
||||
className="ChatBadge miniapp"
|
||||
pill
|
||||
fluid
|
||||
size="tiny"
|
||||
onClick={handleOpenApp}
|
||||
>
|
||||
{oldLang('BotOpen')}
|
||||
</Button>
|
||||
)}
|
||||
{shouldRenderMuteModal && (
|
||||
<MuteChatModal
|
||||
isOpen={isMuteModalOpen}
|
||||
|
||||
@ -119,6 +119,7 @@ const RecentContacts: FC<OwnProps & StateProps> = ({
|
||||
{recentlyFoundChatIds.map((id) => (
|
||||
<LeftSearchResultChat
|
||||
chatId={id}
|
||||
isRecent
|
||||
onClick={handleClick}
|
||||
/>
|
||||
))}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user