Message Context Menu: Implement Gift Button (#5384)

This commit is contained in:
Alexander Zinchuk 2025-01-03 17:15:28 +01:00
parent 4daf327b38
commit e42b148721
3 changed files with 46 additions and 3 deletions

View File

@ -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<OwnProps & StateProps> = ({
isWithPaidReaction,
onClose,
onCloseAnimationEnd,
contactUserFullName,
canGift,
}) => {
const {
openThread,
@ -690,6 +698,8 @@ const ContextMenuContainer: FC<OwnProps & StateProps> = ({
onTranslate={handleTranslate}
onShowOriginal={handleShowOriginal}
onSelectLanguage={handleSelectLanguage}
contactUserFullName={contactUserFullName}
canGift={canGift}
/>
<PinMessageModal
isOpen={isPinModalOpen}
@ -719,6 +729,9 @@ export default memo(withGlobal<OwnProps>(
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<OwnProps>(
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<OwnProps>(
isWithPaidReaction: chatFullInfo?.isPaidReactionAvailable,
poll,
story,
contactUserFullName,
canGift,
};
},
)(ContextMenuContainer));

View File

@ -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<OwnProps> = ({
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<HTMLDivElement>(null);
@ -227,6 +235,12 @@ const MessageContextMenu: FC<OwnProps> = ({
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<OwnProps> = ({
onClose();
});
const handleGiftClick = useLastCallback(() => {
openGiftModal({ forUserId: message.chatId });
onClose();
});
useEffect(() => {
if (isOpen && areItemsHidden && !isReactionPickerOpen) {
onClose();
@ -379,6 +398,13 @@ const MessageContextMenu: FC<OwnProps> = ({
)}
dir={lang.isRtl ? 'rtl' : undefined}
>
{shouldShowGiftButton
&& (
<MenuItem icon="gift" onClick={handleGiftClick}>
{message?.isOutgoing ? lang('SendAnotherGift')
: lang('Conversation.ContextMenuSendGiftTo', contactUserFullName)}
</MenuItem>
)}
{canSendNow && <MenuItem icon="send-outline" onClick={onSend}>{lang('MessageScheduleSend')}</MenuItem>}
{canReschedule && (
<MenuItem icon="schedule" onClick={onReschedule}>{lang('MessageScheduleEditTime')}</MenuItem>

View File

@ -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';