import type { FC } from '../../../../lib/teact/teact'; import React, { memo, useCallback, useEffect } from '../../../../lib/teact/teact'; import { getActions, withGlobal } from '../../../../global'; import type { ApiLimitTypeWithModal } from '../../../../api/types'; import type { OldLangFn } from '../../../../hooks/useOldLang'; import type { IconName } from '../../../../types/icons'; import { MAX_UPLOAD_FILEPART_SIZE } from '../../../../config'; import { selectIsCurrentUserPremium, selectIsPremiumPurchaseBlocked } from '../../../../global/selectors'; import buildClassName from '../../../../util/buildClassName'; import { formatFileSize } from '../../../../util/textFormat'; import renderText from '../../../common/helpers/renderText'; import useFlag from '../../../../hooks/useFlag'; import useOldLang from '../../../../hooks/useOldLang'; import Icon from '../../../common/icons/Icon'; import Button from '../../../ui/Button'; import Modal from '../../../ui/Modal'; import PremiumLimitsCompare from './PremiumLimitsCompare'; import styles from './PremiumLimitReachedModal.module.scss'; const LIMIT_DESCRIPTION: Record = { dialogFiltersChats: 'LimitReachedChatInFolders', uploadMaxFileparts: 'LimitReachedFileSize', dialogFilters: 'LimitReachedFolders', dialogFolderPinned: 'LimitReachedPinDialogs', channelsPublic: 'LimitReachedPublicLinks', channels: 'LimitReachedCommunities', chatlistInvites: 'LimitReachedFolderLinks', chatlistJoined: 'LimitReachedSharedFolders', savedDialogsPinned: 'LimitReachedPinSavedDialogs', }; const LIMIT_DESCRIPTION_BLOCKED: Record = { dialogFiltersChats: 'LimitReachedChatInFoldersLocked', uploadMaxFileparts: 'LimitReachedFileSizeLocked', dialogFilters: 'LimitReachedFoldersLocked', dialogFolderPinned: 'LimitReachedPinDialogsLocked', channelsPublic: 'LimitReachedPublicLinksLocked', channels: 'LimitReachedCommunitiesLocked', chatlistInvites: 'LimitReachedFolderLinksLocked', chatlistJoined: 'LimitReachedSharedFoldersLocked', savedDialogsPinned: 'LimitReachedPinSavedDialogsLocked', }; const LIMIT_DESCRIPTION_PREMIUM: Record = { dialogFiltersChats: 'LimitReachedChatInFoldersPremium', uploadMaxFileparts: 'LimitReachedFileSizePremium', dialogFilters: 'LimitReachedFoldersPremium', dialogFolderPinned: 'LimitReachedPinDialogsPremium', channelsPublic: 'LimitReachedPublicLinksPremium', channels: 'LimitReachedCommunitiesPremium', chatlistInvites: 'LimitReachedFolderLinksPremium', chatlistJoined: 'LimitReachedSharedFoldersPremium', savedDialogsPinned: 'LimitReachedPinSavedDialogsPremium', }; const LIMIT_ICON: Record = { dialogFiltersChats: 'chat-badge', uploadMaxFileparts: 'file-badge', dialogFilters: 'folder-badge', dialogFolderPinned: 'pin-badge', channelsPublic: 'link-badge', channels: 'chats-badge', chatlistInvites: 'link-badge', chatlistJoined: 'folder-badge', savedDialogsPinned: 'pin-badge', }; const LIMIT_VALUE_FORMATTER: Partial string>> = { uploadMaxFileparts: (lang: OldLangFn, value: number) => { // The real size is not exactly 4gb, so we need to round it if (value === 8000) return lang('FileSize.GB', '4'); if (value === 4000) return lang('FileSize.GB', '2'); return formatFileSize(lang, value * MAX_UPLOAD_FILEPART_SIZE); }, }; function getLimiterDescription({ lang, limitType, isPremium, canBuyPremium, defaultValue, premiumValue, valueFormatter, }: { lang: OldLangFn; limitType?: ApiLimitTypeWithModal; isPremium?: boolean; canBuyPremium?: boolean; defaultValue?: number; premiumValue?: number; valueFormatter?: (...args: any[]) => string; }) { if (!limitType) { return undefined; } const defaultValueFormatted = valueFormatter ? valueFormatter(lang, defaultValue) : defaultValue; const premiumValueFormatted = valueFormatter ? valueFormatter(lang, premiumValue) : premiumValue; if (isPremium) { return lang(LIMIT_DESCRIPTION_PREMIUM[limitType], premiumValueFormatted); } return canBuyPremium ? lang(LIMIT_DESCRIPTION[limitType], limitType === 'channelsPublic' ? premiumValueFormatted : [defaultValueFormatted, premiumValueFormatted]) : lang(LIMIT_DESCRIPTION_BLOCKED[limitType], defaultValueFormatted); } export type OwnProps = { limit?: ApiLimitTypeWithModal; }; type StateProps = { defaultValue?: number; premiumValue?: number; isPremium?: boolean; canBuyPremium?: boolean; }; const PremiumLimitReachedModal: FC = ({ defaultValue, premiumValue, limit, isPremium, canBuyPremium, }) => { const { closeLimitReachedModal, openPremiumModal } = getActions(); const lang = useOldLang(); const [isClosing, startClosing, stopClosing] = useFlag(); const handleClick = useCallback(() => { openPremiumModal(); startClosing(); }, [openPremiumModal, startClosing]); useEffect(() => { if (!limit && isClosing) stopClosing(); }, [isClosing, limit, stopClosing]); const title = lang('LimitReached'); const valueFormatter = limit && LIMIT_VALUE_FORMATTER[limit]; const description = getLimiterDescription({ lang, limitType: limit, isPremium, canBuyPremium, defaultValue, premiumValue, valueFormatter, }); const icon = limit && LIMIT_ICON[limit]; const canUpgrade = canBuyPremium && !isPremium; return ( {!canUpgrade && (
{valueFormatter?.( lang, isPremium ? premiumValue : defaultValue, ) || (isPremium ? premiumValue : defaultValue)}
)} {canUpgrade && ( )}
{renderText(description || '', ['simple_markdown', 'br'])}
{canUpgrade && ( )}
); }; export default memo(withGlobal( (global, { limit }): StateProps => { const { limits } = global.appConfig || {}; const isPremium = selectIsCurrentUserPremium(global); return { defaultValue: limit ? limits?.[limit][0] : undefined, premiumValue: limit ? limits?.[limit][1] : undefined, canBuyPremium: !selectIsPremiumPurchaseBlocked(global), isPremium, }; }, )(PremiumLimitReachedModal));