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