import React, { memo, useEffect, useMemo } from '../../../lib/teact/teact'; import { getActions, withGlobal } from '../../../global'; import type { ApiChat, ApiChatFullInfo, ApiMyBoost } from '../../../api/types'; import type { TabState } from '../../../global/types'; import { getChatTitle, isChatAdmin, isChatChannel } from '../../../global/helpers'; import { selectChat, selectChatFullInfo, selectIsCurrentUserPremium } from '../../../global/selectors'; import buildClassName from '../../../util/buildClassName'; import { formatShortDuration } from '../../../util/dates/dateFormat'; import { getServerTime } from '../../../util/serverTime'; import { getBoostProgressInfo } from '../../common/helpers/boostInfo'; import renderText from '../../common/helpers/renderText'; import useFlag from '../../../hooks/useFlag'; import useLang from '../../../hooks/useLang'; import useLastCallback from '../../../hooks/useLastCallback'; import useOldLang from '../../../hooks/useOldLang'; import Avatar from '../../common/Avatar'; import Icon from '../../common/icons/Icon'; import PremiumProgress from '../../common/PremiumProgress'; import Button from '../../ui/Button'; import ConfirmDialog from '../../ui/ConfirmDialog'; import Loading from '../../ui/Loading'; import Modal from '../../ui/Modal'; import styles from './BoostModal.module.scss'; type LoadedParams = { boost?: ApiMyBoost; leftText: string; rightText?: string; value: string; progress: number; descriptionText: string; isBoosted?: boolean; canBoostMore?: boolean; }; type BoostInfo = ({ isStatusLoaded: false; title: string; } & Undefined) | ({ isStatusLoaded: true; title: string; } & LoadedParams); export type OwnProps = { modal: TabState['boostModal']; }; type StateProps = { chat?: ApiChat; chatFullInfo?: ApiChatFullInfo; prevBoostedChat?: ApiChat; isCurrentUserPremium?: boolean; }; const BoostModal = ({ modal, chat, chatFullInfo, prevBoostedChat, isCurrentUserPremium, }: OwnProps & StateProps) => { const { applyBoost, closeBoostModal, requestConfetti, openPremiumModal, loadFullChat, } = getActions(); const [isReplaceModalOpen, openReplaceModal, closeReplaceModal] = useFlag(); const [isWaitDialogOpen, openWaitDialog, closeWaitDialog] = useFlag(); const [isPremiumDialogOpen, openPremiumDialog, closePremiumDialog] = useFlag(); const isChannel = chat && isChatChannel(chat); const isOpen = Boolean(modal); const oldLang = useOldLang(); const lang = useLang(); useEffect(() => { if (chat && !chatFullInfo) { loadFullChat({ chatId: chat.id }); } }, [chat, chatFullInfo]); const chatTitle = useMemo(() => { if (!chat) { return undefined; } return getChatTitle(oldLang, chat); }, [chat, oldLang]); const boostedChatTitle = useMemo(() => { if (!prevBoostedChat) { return undefined; } return getChatTitle(oldLang, prevBoostedChat); }, [prevBoostedChat, oldLang]); const { isStatusLoaded, isBoosted, boost, title, leftText, rightText, value, progress, descriptionText, canBoostMore, }: BoostInfo = useMemo(() => { if (!modal?.boostStatus || !chat) { return { isStatusLoaded: false, title: oldLang('Loading'), }; } const { hasMyBoost, } = modal.boostStatus; const firstBoost = modal?.myBoosts && getFirstAvailableBoost(modal.myBoosts, chat.id); const areBoostsInDifferentChannels = modal?.myBoosts && !areAllBoostsInChannel(modal.myBoosts, chat.id); const { boosts, currentLevel, hasNextLevel, levelProgress, remainingBoosts, isMaxLevel, } = getBoostProgressInfo(modal.boostStatus, true); const hasBoost = hasMyBoost; const left = oldLang('BoostsLevel', currentLevel); const right = hasNextLevel ? oldLang('BoostsLevel', currentLevel + 1) : undefined; const moreBoosts = oldLang('ChannelBoost.MoreBoosts', remainingBoosts); const modalTitle = isChannel ? oldLang('BoostChannel') : oldLang('BoostGroup'); const boostsLeftToUnrestrict = (chatFullInfo?.boostsToUnrestrict || 0) - (chatFullInfo?.boostsApplied || 0); let description: string | undefined; if (isMaxLevel) { description = oldLang('BoostsMaxLevelReached'); } else if (boostsLeftToUnrestrict > 0 && !isChatAdmin(chat)) { const boostTimes = oldLang('GroupBoost.BoostToUnrestrict.Times', boostsLeftToUnrestrict); description = oldLang('GroupBoost.BoostToUnrestrict', [boostTimes, chatTitle]); } else { description = oldLang('ChannelBoost.MoreBoostsNeeded.Text', [chatTitle, moreBoosts]); } return { isStatusLoaded: true, title: modalTitle, leftText: left, rightText: right, value: boosts.toString(), progress: levelProgress, remainingBoosts, descriptionText: description, boost: firstBoost, isBoosted: hasBoost, canBoostMore: areBoostsInDifferentChannels && !isMaxLevel, }; }, [chat, chatTitle, modal, oldLang, chatFullInfo, isChannel]); const isBoostDisabled = !modal?.myBoosts?.length && isCurrentUserPremium; const isReplacingBoost = boost?.chatId && boost.chatId !== modal?.chatId; const handleApplyBoost = useLastCallback(() => { closeReplaceModal(); applyBoost({ chatId: chat!.id, slots: [boost!.slot] }); requestConfetti({}); }); const handleProceedPremium = useLastCallback(() => { openPremiumModal(); closePremiumDialog(); closeBoostModal(); }); const handleButtonClick = useLastCallback(() => { if (!boost) { if (!isCurrentUserPremium) { openPremiumDialog(); return; } closeBoostModal(); return; } if (!canBoostMore) { closeBoostModal(); return; } if (boost.cooldownUntil) { openWaitDialog(); return; } if (isReplacingBoost) { openReplaceModal(); return; } handleApplyBoost(); }); const handleCloseClick = useLastCallback(() => { closeBoostModal(); }); function renderContent() { if (!isStatusLoaded) { return ; } return ( <> {isBoosted && (
{oldLang('ChannelBoost.YouBoostedChannelText', chatTitle)}
)}
{renderText(descriptionText, ['simple_markdown', 'emoji'])}
); } return ( {renderContent()} {isReplacingBoost && boostedChatTitle && (
{renderText( oldLang('ChannelBoost.ReplaceBoost', [boostedChatTitle, chatTitle]), ['simple_markdown', 'emoji'], )}
)} {Boolean(boost?.cooldownUntil) && ( {renderText( oldLang( 'ChannelBoost.Error.BoostTooOftenText', formatShortDuration(lang, boost!.cooldownUntil - getServerTime()), ), ['simple_markdown', 'emoji'], )} )} {!isCurrentUserPremium && ( {renderText(oldLang('PremiumNeededForBoosting'), ['simple_markdown', 'emoji'])} )}
); }; function getFirstAvailableBoost(myBoosts: ApiMyBoost[], chatId?: string) { return myBoosts.find((boost) => !boost.chatId) || myBoosts.filter((b) => chatId && b.chatId !== chatId) .sort((a, b) => a.date - b.date)[0]; } function areAllBoostsInChannel(myBoosts: ApiMyBoost[], chatId: string) { return myBoosts.every((boost) => boost.chatId === chatId); } export default memo(withGlobal( (global, { modal }): StateProps => { const chat = modal && selectChat(global, modal?.chatId); const chatFullInfo = chat && selectChatFullInfo(global, chat.id); const firstBoost = modal?.myBoosts && getFirstAvailableBoost(modal.myBoosts, modal.chatId); const boostedChat = firstBoost?.chatId ? selectChat(global, firstBoost?.chatId) : undefined; return { chat, chatFullInfo, prevBoostedChat: boostedChat, isCurrentUserPremium: selectIsCurrentUserPremium(global), }; }, )(BoostModal));