import type { FC } from '@teact'; import { memo, useEffect, useMemo, useRef, useState } from '@teact'; import { getActions, withGlobal } from '../../../global'; import type { ApiPremiumPromo, ApiPremiumSection, ApiPremiumSubscriptionOption, ApiStarGift, ApiSticker, ApiStickerSet, ApiUser, } from '../../../api/types'; import type { GlobalState } from '../../../global/types'; import type { LangPair } from '../../../types/language'; import { PREMIUM_FEATURE_SECTIONS, TME_LINK_PREFIX } from '../../../config'; import { getUserFullName } from '../../../global/helpers'; import { selectCustomEmoji, selectIsCurrentUserPremium, selectStickerSet, selectTabState, selectUser, } from '../../../global/selectors'; import { selectPremiumLimit } from '../../../global/selectors/limits'; import buildClassName from '../../../util/buildClassName'; import { formatCountdownDays } from '../../../util/dates/oldDateFormat'; import { formatCurrency } from '../../../util/formatCurrency'; import { getStickerFromGift } from '../../common/helpers/gifts'; import { REM } from '../../common/helpers/mediaDimensions'; import renderText from '../../common/helpers/renderText'; import { renderTextWithEntities } from '../../common/helpers/renderTextWithEntities'; import useLang from '../../../hooks/useLang'; import useLastCallback from '../../../hooks/useLastCallback'; import useOldLang from '../../../hooks/useOldLang'; import useSyncEffect from '../../../hooks/useSyncEffect'; import CustomEmoji from '../../common/CustomEmoji'; import ParticlesHeader from '../../modals/common/ParticlesHeader.tsx'; import Button from '../../ui/Button'; import Modal from '../../ui/Modal'; import Transition from '../../ui/Transition'; import PremiumFeatureItem from './PremiumFeatureItem'; import PremiumFeatureModal, { PREMIUM_FEATURE_DESCRIPTIONS, PREMIUM_FEATURE_TITLES } from './PremiumFeatureModal'; import PremiumSubscriptionOption from './PremiumSubscriptionOption'; import styles from './PremiumMainModal.module.scss'; import PremiumAds from '../../../assets/premium/PremiumAds.svg'; import PremiumAi from '../../../assets/premium/PremiumAi.svg'; import PremiumBadge from '../../../assets/premium/PremiumBadge.svg'; import PremiumChats from '../../../assets/premium/PremiumChats.svg'; import PremiumEffects from '../../../assets/premium/PremiumEffects.svg'; import PremiumEmoji from '../../../assets/premium/PremiumEmoji.svg'; import PremiumFile from '../../../assets/premium/PremiumFile.svg'; import PremiumLastSeen from '../../../assets/premium/PremiumLastSeen.svg'; import PremiumLimits from '../../../assets/premium/PremiumLimits.svg'; import PremiumMessagePrivacy from '../../../assets/premium/PremiumMessagePrivacy.svg'; import PremiumNoforwards from '../../../assets/premium/PremiumNoForwardsPrivacy.svg'; import PremiumReactions from '../../../assets/premium/PremiumReactions.svg'; import PremiumSpeed from '../../../assets/premium/PremiumSpeed.svg'; import PremiumStatus from '../../../assets/premium/PremiumStatus.svg'; import PremiumStickers from '../../../assets/premium/PremiumStickers.svg'; import PremiumTags from '../../../assets/premium/PremiumTags.svg'; import PremiumTranslate from '../../../assets/premium/PremiumTranslate.svg'; import PremiumVideo from '../../../assets/premium/PremiumVideo.svg'; import PremiumVoice from '../../../assets/premium/PremiumVoice.svg'; const LIMIT_ACCOUNTS = 4; const STATUS_EMOJI_SIZE = 8 * REM; const PREMIUM_FEATURE_COLOR_ICONS: Record = { stories: PremiumStatus, double_limits: PremiumLimits, infinite_reactions: PremiumReactions, premium_stickers: PremiumStickers, animated_emoji: PremiumEmoji, no_ads: PremiumAds, voice_to_text: PremiumVoice, profile_badge: PremiumBadge, faster_download: PremiumSpeed, more_upload: PremiumFile, advanced_chat_management: PremiumChats, animated_userpics: PremiumVideo, emoji_status: PremiumStatus, translations: PremiumTranslate, saved_tags: PremiumTags, last_seen: PremiumLastSeen, message_privacy: PremiumMessagePrivacy, effects: PremiumEffects, ai_compose: PremiumAi, todo: PremiumBadge, pm_noforwards: PremiumNoforwards, }; export type OwnProps = { isOpen?: boolean; }; type StateProps = { currentUserId?: string; promo?: ApiPremiumPromo; fromUser?: ApiUser; fromUserStatusEmoji?: ApiSticker; fromUserStatusSet?: ApiStickerSet; toUser?: ApiUser; initialSection?: ApiPremiumSection; isPremium?: boolean; isSuccess?: boolean; isGift?: boolean; daysAmount?: number; gift?: ApiStarGift; limitChannels: number; limitPins: number; limitLinks: number; limitFolders: number; limits?: NonNullable['limits']; premiumSlug?: string; premiumBotUsername?: string; premiumPromoOrder?: ApiPremiumSection[]; }; const PremiumMainModal: FC = ({ isOpen, currentUserId, fromUser, fromUserStatusEmoji, fromUserStatusSet, promo, initialSection, isPremium, limitChannels, limitLinks, limitFolders, limitPins, limits, premiumSlug, premiumBotUsername, isSuccess, isGift, toUser, daysAmount, premiumPromoOrder, gift, }) => { const dialogRef = useRef(); const { closePremiumModal, openInvoice, requestConfetti, openTelegramLink, loadStickers, openStickerSet, } = getActions(); const oldLang = useOldLang(); const lang = useLang(); const [isHeaderHidden, setIsHeaderHidden] = useState(true); const [currentSection, setCurrentSection] = useState(initialSection); const [selectedSubscriptionOption, setSelectedSubscriptionOption] = useState(); useEffect(() => { if (!isOpen) { setIsHeaderHidden(true); setCurrentSection(undefined); } else if (initialSection) { setCurrentSection(initialSection); } }, [isOpen, initialSection]); const handleOpenSection = useLastCallback((section: ApiPremiumSection) => { setCurrentSection(section); }); const handleResetSection = useLastCallback(() => { setCurrentSection(undefined); }); function handleScroll(e: React.UIEvent) { const { scrollTop } = e.currentTarget; setIsHeaderHidden(scrollTop <= 150); } const handleClickWithStartParam = useLastCallback((startParam?: string) => { const dialog = dialogRef.current; if (!dialog) return; if (premiumSlug) { openInvoice({ type: 'slug', slug: premiumSlug, }); } else if (premiumBotUsername) { openTelegramLink({ url: `${TME_LINK_PREFIX}${premiumBotUsername}?start=${startParam || 'promo'}`, }); closePremiumModal(); } }); const handleClick = useLastCallback(() => { if (selectedSubscriptionOption) { handleClickWithStartParam(String(selectedSubscriptionOption.months)); } else { handleClickWithStartParam(); } }); const handleChangeSubscriptionOption = useLastCallback((months: number) => { const foundOption = promo?.options.find((option) => option.months === months); setSelectedSubscriptionOption(foundOption); }); const showConfetti = useLastCallback(() => { const dialog = dialogRef.current; if (!dialog) return; if (isOpen) { const { top, left, width, height, } = dialog.querySelector('.modal-content')!.getBoundingClientRect(); requestConfetti({ top, left, width, height, withStars: true, }); } }); useEffect(() => { if (isSuccess) { showConfetti(); } }, [isSuccess, showConfetti]); useSyncEffect(([prevIsPremium]) => { if (prevIsPremium === isPremium) return; showConfetti(); }, [isPremium, showConfetti]); const filteredSections = useMemo(() => { if (!premiumPromoOrder) return PREMIUM_FEATURE_SECTIONS; return premiumPromoOrder.filter((section) => PREMIUM_FEATURE_SECTIONS.includes(section)); }, [premiumPromoOrder]); useEffect(() => { if (!fromUserStatusEmoji || fromUserStatusSet) return; loadStickers({ stickerSetInfo: fromUserStatusEmoji.stickerSetInfo, }); }, [loadStickers, fromUserStatusEmoji, fromUserStatusSet]); useEffect(() => { const [defaultOption] = promo?.options ?? []; setSelectedSubscriptionOption(defaultOption); }, [promo]); const handleOpenStatusSet = useLastCallback(() => { if (!fromUserStatusSet) return; openStickerSet({ stickerSetInfo: fromUserStatusSet, }); }); const fullMonthlyAmount = useMemo(() => { const monthOption = promo?.options.find((option) => option.months === 1); if (!monthOption) { return undefined; } return Number(monthOption.amount); }, [promo]); const subscribeButtonText = useMemo(() => { if (!selectedSubscriptionOption) { return undefined; } const { amount, months, currency } = selectedSubscriptionOption; const perMonthPrice = Math.floor(amount / months); return formatCurrency( lang, perMonthPrice, currency, ); }, [selectedSubscriptionOption, lang]); if (!promo || (fromUserStatusEmoji && !fromUserStatusSet)) return undefined; function getHeaderText() { if (gift) { return lang('PremiumGiftHeader'); } if (isGift) { const formattedDuration = daysAmount ? formatCountdownDays(lang, daysAmount) : ''; return renderText( fromUser?.id === currentUserId ? lang('DialogTitlePremiumGiftSentTo', { user: getUserFullName(toUser), amount: formattedDuration }) : lang('DialogTitlePremiumGiftReceivedFrom', { user: getUserFullName(fromUser), amount: formattedDuration }), ['simple_markdown', 'emoji'], ); } if (fromUserStatusSet && fromUser) { const template = oldLang('lng_premium_emoji_status_title').replace('{user}', getUserFullName(fromUser)!); const [first, second] = template.split('{link}'); const emoji = fromUserStatusSet.thumbCustomEmojiId ? ( ) : undefined; const link = ( {emoji} {renderText(fromUserStatusSet.title)} ); return [renderText(first), link, renderText(second)]; } return renderText( fromUser ? oldLang('TelegramPremiumUserDialogTitle', getUserFullName(fromUser)) : oldLang(isPremium ? 'TelegramPremiumSubscribedTitle' : 'TelegramPremium'), ['simple_markdown', 'emoji'], ); } function getHeaderDescription() { if (gift && gift.type !== 'starGiftUnique' && gift.perUserTotal) { return lang('DescriptionGiftPremiumRequired2', { count: gift.perUserTotal }, { pluralValue: gift.perUserTotal, }); } if (isGift) { return fromUser?.id === currentUserId ? oldLang('TelegramPremiumUserGiftedPremiumOutboundDialogSubtitle', getUserFullName(toUser)) : oldLang('TelegramPremiumUserGiftedPremiumDialogSubtitle'); } if (fromUserStatusSet) { return oldLang('TelegramPremiumUserStatusDialogSubtitle'); } return fromUser ? oldLang('TelegramPremiumUserDialogSubtitle') : oldLang(isPremium ? 'TelegramPremiumSubscribedSubtitle' : 'TelegramPremiumSubtitle'); } function renderHeader() { if (gift) { const giftSticker = getStickerFromGift(gift); return ( ); } if (!fromUserStatusEmoji) { return ( ); } return ( <>

{getHeaderText()}

{renderText(getHeaderDescription(), ['simple_markdown', 'emoji'])}
); } function renderFooterText() { if (!promo || (isGift && fromUser?.id === currentUserId)) { return undefined; } return (
{renderTextWithEntities({ text: promo.statusText, entities: promo.statusEntities, })}
); } function renderSubscriptionOptions() { return (
{promo?.options .map((option) => ( ))}
); } return ( {!currentSection ? (
{renderHeader()} {!isPremium && !isGift && renderSubscriptionOptions()}

{oldLang('TelegramPremium')}

{filteredSections.map((section, index) => { const shouldUseNewLang = section === 'todo' || section === 'pm_noforwards' || section === 'ai_compose'; return ( ); })}

{renderText(oldLang('AboutPremiumDescription'), ['simple_markdown'])}

{renderText(oldLang('AboutPremiumDescription2'), ['simple_markdown'])}

{renderFooterText()}
{!isPremium && selectedSubscriptionOption && (
)}
) : ( )}
); }; export default memo(withGlobal((global): Complete => { const { premiumModal, } = selectTabState(global); const fromUser = premiumModal?.fromUserId ? selectUser(global, premiumModal.fromUserId) : undefined; const fromUserStatusEmoji = fromUser?.emojiStatus ? selectCustomEmoji(global, fromUser.emojiStatus.documentId) : undefined; const fromUserStatusSet = fromUserStatusEmoji ? selectStickerSet(global, fromUserStatusEmoji.stickerSetInfo) : undefined; return { currentUserId: global.currentUserId, promo: premiumModal?.promo, isSuccess: premiumModal?.isSuccess, isGift: premiumModal?.isGift, daysAmount: premiumModal?.daysAmount, gift: premiumModal?.gift, fromUser, fromUserStatusEmoji, fromUserStatusSet, toUser: premiumModal?.toUserId ? selectUser(global, premiumModal.toUserId) : undefined, initialSection: premiumModal?.initialSection, isPremium: selectIsCurrentUserPremium(global), limitChannels: selectPremiumLimit(global, 'channels'), limitFolders: selectPremiumLimit(global, 'dialogFilters'), limitPins: selectPremiumLimit(global, 'dialogFolderPinned'), limitLinks: selectPremiumLimit(global, 'channelsPublic'), limits: global.appConfig.limits, premiumSlug: global.appConfig.premiumInvoiceSlug, premiumBotUsername: global.appConfig.premiumBotUsername, premiumPromoOrder: global.appConfig.premiumPromoOrder, }; })(PremiumMainModal));