diff --git a/src/components/middle/message/ContextMenuContainer.tsx b/src/components/middle/message/ContextMenuContainer.tsx index 6f697da95..7d35ea2d1 100644 --- a/src/components/middle/message/ContextMenuContainer.tsx +++ b/src/components/middle/message/ContextMenuContainer.tsx @@ -32,6 +32,8 @@ import { getIsDownloading, getMessageDownloadableMedia, getMessageVideo, + getPrivateChatUserId, + getUserFullName, hasMessageTtl, isActionMessage, isChatChannel, @@ -46,6 +48,7 @@ import { selectAllowedMessageActionsSlow, selectBot, selectCanForwardMessage, + selectCanGift, selectCanPlayAnimatedEmojis, selectCanScheduleUntilOnline, selectCanTranslateMessage, @@ -67,6 +70,7 @@ import { selectStickerSet, selectThreadInfo, selectTopic, + selectUser, selectUserStatus, } from '../../../global/selectors'; import { copyTextToClipboard } from '../../../util/clipboard'; @@ -149,6 +153,8 @@ type StateProps = { isChannel?: boolean; canReplyInChat?: boolean; isWithPaidReaction?: boolean; + contactUserFullName?: string; + canGift?: boolean; }; const selection = window.getSelection(); @@ -214,6 +220,8 @@ const ContextMenuContainer: FC = ({ isWithPaidReaction, onClose, onCloseAnimationEnd, + contactUserFullName, + canGift, }) => { const { openThread, @@ -690,6 +698,8 @@ const ContextMenuContainer: FC = ({ onTranslate={handleTranslate} onShowOriginal={handleShowOriginal} onSelectLanguage={handleSelectLanguage} + contactUserFullName={contactUserFullName} + canGift={canGift} /> ( const chat = selectChat(global, message.chatId); const isPrivate = chat && isUserId(chat.id); const chatFullInfo = !isPrivate ? selectChatFullInfo(global, message.chatId) : undefined; + const contactUserFullName = chat && isUserId(chat.id) + ? getUserFullName(selectUser(global, getPrivateChatUserId(chat)!)) + : undefined; const { seenByExpiresAt, seenByMaxChatMembers, maxUniqueReactions, readDateExpiresAt, @@ -815,6 +828,8 @@ export default memo(withGlobal( const storyData = message.content.storyData; const story = storyData ? selectPeerStory(global, storyData.peerId, storyData.id) : undefined; + const canGift = selectCanGift(global, message.chatId); + return { threadId, chat, @@ -868,6 +883,8 @@ export default memo(withGlobal( isWithPaidReaction: chatFullInfo?.isPaidReactionAvailable, poll, story, + contactUserFullName, + canGift, }; }, )(ContextMenuContainer)); diff --git a/src/components/middle/message/MessageContextMenu.tsx b/src/components/middle/message/MessageContextMenu.tsx index 733ce75a0..f12426739 100644 --- a/src/components/middle/message/MessageContextMenu.tsx +++ b/src/components/middle/message/MessageContextMenu.tsx @@ -19,7 +19,11 @@ import type { } from '../../../api/types'; import type { IAnchorPosition } from '../../../types'; -import { getUserFullName, groupStatetefulContent, isUserId } from '../../../global/helpers'; +import { + getUserFullName, + groupStatetefulContent, + isUserId, +} from '../../../global/helpers'; import buildClassName from '../../../util/buildClassName'; import { disableScrolling } from '../../../util/scrollLock'; import { REM } from '../../common/helpers/mediaDimensions'; @@ -125,6 +129,8 @@ type OwnProps = { onSendPaidReaction?: NoneToVoidFunction; onShowPaidReactionModal?: NoneToVoidFunction; onReactionPickerOpen?: (position: IAnchorPosition) => void; + contactUserFullName?: string; + canGift?: boolean; }; const SCROLLBAR_WIDTH = 10; @@ -214,9 +220,11 @@ const MessageContextMenu: FC = ({ onTranslate, onShowOriginal, onSelectLanguage, + contactUserFullName, + canGift, }) => { const { - showNotification, openStickerSet, openCustomEmojiSets, loadStickers, + showNotification, openStickerSet, openCustomEmojiSets, loadStickers, openGiftModal, } = getActions(); // eslint-disable-next-line no-null/no-null const menuRef = useRef(null); @@ -227,6 +235,12 @@ const MessageContextMenu: FC = ({ const withReactions = canShowReactionList && !noReactions; const isEdited = ('isEdited' in message) && message.isEdited; const seenByDates = message.seenByDates; + const isPremiumGift = message.content.action?.type === 'giftPremium'; + const isGiftCode = message.content.action?.type === 'giftCode'; + const isStarsGift = message.content.action?.type === 'giftStars'; + const isStarGift = message.content.action?.type === 'starGift'; + const shouldShowGiftButton = isUserId(message.chatId) + && canGift && (isPremiumGift || isGiftCode || isStarsGift || isStarGift); const [areItemsHidden, hideItems] = useFlag(); const [isReady, markIsReady, unmarkIsReady] = useFlag(); @@ -240,6 +254,11 @@ const MessageContextMenu: FC = ({ onClose(); }); + const handleGiftClick = useLastCallback(() => { + openGiftModal({ forUserId: message.chatId }); + onClose(); + }); + useEffect(() => { if (isOpen && areItemsHidden && !isReactionPickerOpen) { onClose(); @@ -379,6 +398,13 @@ const MessageContextMenu: FC = ({ )} dir={lang.isRtl ? 'rtl' : undefined} > + {shouldShowGiftButton + && ( + + {message?.isOutgoing ? lang('SendAnotherGift') + : lang('Conversation.ContextMenuSendGiftTo', contactUserFullName)} + + )} {canSendNow && {lang('MessageScheduleSend')}} {canReschedule && ( {lang('MessageScheduleEditTime')} diff --git a/src/config.ts b/src/config.ts index 7571003ca..7b1b48de4 100644 --- a/src/config.ts +++ b/src/config.ts @@ -52,7 +52,7 @@ export const MEDIA_PROGRESSIVE_CACHE_DISABLED = false; export const MEDIA_PROGRESSIVE_CACHE_NAME = 'tt-media-progressive'; export const MEDIA_CACHE_MAX_BYTES = 512 * 1024; // 512 KB export const CUSTOM_BG_CACHE_NAME = 'tt-custom-bg'; -export const LANG_CACHE_NAME = 'tt-lang-packs-v46'; +export const LANG_CACHE_NAME = 'tt-lang-packs-v47'; export const ASSET_CACHE_NAME = 'tt-assets'; export const AUTODOWNLOAD_FILESIZE_MB_LIMITS = [1, 5, 10, 50, 100, 500]; export const DATA_BROADCAST_CHANNEL_NAME = 'tt-global';