import React, { memo, useCallback, useEffect, useLayoutEffect, useRef, useState, } from '../../../lib/teact/teact'; import { getActions, withGlobal } from '../../../global'; import type { FC } from '../../../lib/teact/teact'; import type { ApiSticker, ApiVideo } from '../../../api/types'; import type { GlobalActions } from '../../../global/types'; import { IS_TOUCH_ENV } from '../../../util/environment'; import { fastRaf } from '../../../util/schedulers'; import buildClassName from '../../../util/buildClassName'; import { selectIsCurrentUserPremium } from '../../../global/selectors'; import useShowTransition from '../../../hooks/useShowTransition'; import useMouseInside from '../../../hooks/useMouseInside'; import useLang from '../../../hooks/useLang'; import useAppLayout from '../../../hooks/useAppLayout'; import Button from '../../ui/Button'; import Menu from '../../ui/Menu'; import Transition from '../../ui/Transition'; import EmojiPicker from './EmojiPicker'; import CustomEmojiPicker from './CustomEmojiPicker'; import StickerPicker from './StickerPicker'; import GifPicker from './GifPicker'; import SymbolMenuFooter, { SYMBOL_MENU_TAB_TITLES, SymbolMenuTabs } from './SymbolMenuFooter'; import Portal from '../../ui/Portal'; import './SymbolMenu.scss'; const ANIMATION_DURATION = 350; export type OwnProps = { chatId: string; threadId?: number; isOpen: boolean; canSendStickers: boolean; canSendGifs: boolean; onLoad: () => void; onClose: () => void; onEmojiSelect: (emoji: string) => void; onCustomEmojiSelect: (emoji: ApiSticker) => void; onStickerSelect: ( sticker: ApiSticker, isSilent?: boolean, shouldSchedule?: boolean, shouldPreserveInput?: boolean, shouldUpdateStickerSetsOrder?: boolean ) => void; onGifSelect: (gif: ApiVideo, isSilent?: boolean, shouldSchedule?: boolean) => void; onRemoveSymbol: () => void; onSearchOpen: (type: 'stickers' | 'gifs') => void; addRecentEmoji: GlobalActions['addRecentEmoji']; addRecentCustomEmoji: GlobalActions['addRecentCustomEmoji']; }; type StateProps = { isLeftColumnShown: boolean; isCurrentUserPremium?: boolean; lastSyncTime?: number; }; let isActivated = false; const SymbolMenu: FC = ({ chatId, threadId, isOpen, canSendStickers, canSendGifs, isLeftColumnShown, isCurrentUserPremium, lastSyncTime, onLoad, onClose, onEmojiSelect, onCustomEmojiSelect, onStickerSelect, onGifSelect, onRemoveSymbol, onSearchOpen, addRecentEmoji, addRecentCustomEmoji, }) => { const { loadPremiumSetStickers, loadFeaturedEmojiStickers } = getActions(); const [activeTab, setActiveTab] = useState(0); const [recentEmojis, setRecentEmojis] = useState([]); const [recentCustomEmojis, setRecentCustomEmojis] = useState([]); const { isMobile } = useAppLayout(); const [handleMouseEnter, handleMouseLeave] = useMouseInside(isOpen, onClose, undefined, isMobile); const { shouldRender, transitionClassNames } = useShowTransition(isOpen, onClose, false, false); if (!isActivated && isOpen) { isActivated = true; } useEffect(() => { onLoad(); }, [onLoad]); useEffect(() => { if (!lastSyncTime) return; if (isCurrentUserPremium) { loadPremiumSetStickers(); } loadFeaturedEmojiStickers(); }, [isCurrentUserPremium, lastSyncTime, loadFeaturedEmojiStickers, loadPremiumSetStickers]); useLayoutEffect(() => { if (!isMobile) { return undefined; } if (isOpen) { document.body.classList.add('enable-symbol-menu-transforms'); document.body.classList.add('is-symbol-menu-open'); } return () => { if (isOpen) { fastRaf(() => { document.body.classList.remove('is-symbol-menu-open'); setTimeout(() => { document.body.classList.remove('enable-symbol-menu-transforms'); }, ANIMATION_DURATION); }); } }; }, [isMobile, isOpen]); const recentEmojisRef = useRef(recentEmojis); recentEmojisRef.current = recentEmojis; useEffect(() => { if (!recentEmojisRef.current.length || isOpen) { return; } recentEmojisRef.current.forEach((name) => { addRecentEmoji({ emoji: name }); }); setRecentEmojis([]); }, [isOpen, addRecentEmoji]); const handleEmojiSelect = useCallback((emoji: string, name: string) => { setRecentEmojis((emojis) => [...emojis, name]); onEmojiSelect(emoji); }, [onEmojiSelect]); const recentCustomEmojisRef = useRef(recentCustomEmojis); recentCustomEmojisRef.current = recentCustomEmojis; useEffect(() => { if (!recentCustomEmojisRef.current.length || isOpen) { return; } recentCustomEmojisRef.current.forEach((documentId) => { addRecentCustomEmoji({ documentId, }); }); setRecentEmojis([]); }, [isOpen, addRecentCustomEmoji]); const handleCustomEmojiSelect = useCallback((emoji: ApiSticker) => { setRecentCustomEmojis((ids) => [...ids, emoji.id]); onCustomEmojiSelect(emoji); }, [onCustomEmojiSelect]); const handleSearch = useCallback((type: 'stickers' | 'gifs') => { onClose(); onSearchOpen(type); }, [onClose, onSearchOpen]); const handleStickerSelect = useCallback(( sticker: ApiSticker, isSilent?: boolean, shouldSchedule?: boolean, shouldUpdateStickerSetsOrder?: boolean, ) => { onStickerSelect(sticker, isSilent, shouldSchedule, true, shouldUpdateStickerSetsOrder); }, [onStickerSelect]); const lang = useLang(); function renderContent(isActive: boolean, isFrom: boolean) { switch (activeTab) { case SymbolMenuTabs.Emoji: return ( ); case SymbolMenuTabs.CustomEmoji: return ( ); case SymbolMenuTabs.Stickers: return ( ); case SymbolMenuTabs.GIFs: return ( ); } return undefined; } function stopPropagation(event: any) { event.stopPropagation(); } const content = ( <>
{isActivated && ( {renderContent} )}
{isMobile && ( )} ); if (isMobile) { if (!shouldRender) { return undefined; } const className = buildClassName( 'SymbolMenu mobile-menu', transitionClassNames, isLeftColumnShown && 'left-column-open', ); return (
{content}
); } return ( {content} ); }; export default memo(withGlobal( (global): StateProps => { return { isLeftColumnShown: global.isLeftColumnShown, isCurrentUserPremium: selectIsCurrentUserPremium(global), lastSyncTime: global.lastSyncTime, }; }, )(SymbolMenu));