import { memo, useMemo, useRef, useState } from '@teact'; import { getActions, withGlobal } from '../../../global'; import type { ApiStarGift, ApiTypeCurrencyAmount } from '../../../api/types'; import { STARS_CURRENCY_CODE, TON_CURRENCY_CODE } from '../../../config'; import { selectIsCurrentUserPremium } from '../../../global/selectors'; import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment.ts'; import buildClassName from '../../../util/buildClassName'; import { formatStarsAsIcon, formatTonAsIcon } from '../../../util/localization/format'; import Icon from '../../common/icons/Icon'; ; import { getGiftAttributes, getStickerFromGift } from '../../common/helpers/gifts'; import useFlag from '../../../hooks/useFlag.ts'; import { type ObserveFn, useOnIntersect } from '../../../hooks/useIntersectionObserver'; import useLang from '../../../hooks/useLang'; import useLastCallback from '../../../hooks/useLastCallback'; import GiftRibbon from '../../common/gift/GiftRibbon'; import RadialPatternBackground from '../../common/profile/RadialPatternBackground'; import StickerView from '../../common/StickerView'; import Button from '../../ui/Button'; import styles from './GiftItem.module.scss'; export type OwnProps = { gift: ApiStarGift; isResale?: boolean; withTransferBadge?: boolean; hideBadge?: boolean; noClickable?: boolean; observeIntersection?: ObserveFn; onClick?: (gift: ApiStarGift, target: 'original' | 'resell') => void; }; type StateProps = { isCurrentUserPremium?: boolean; }; const GIFT_STICKER_SIZE = 90; function GiftItemStar({ gift, isResale, isCurrentUserPremium, withTransferBadge, hideBadge, noClickable, observeIntersection, onClick, }: OwnProps & StateProps) { const { openGiftInfoModal, openPremiumModal, showNotification, checkCanSendGift, openGiftAuctionModal, } = getActions(); const ref = useRef(); const stickerRef = useRef(); function getPriceAmount(amounts?: ApiTypeCurrencyAmount[]) { if (!amounts) return { amount: 0, currency: STARS_CURRENCY_CODE }; if (gift.type === 'starGiftUnique' && gift.resaleTonOnly) { const tonAmount = amounts.find((amount) => amount.currency === TON_CURRENCY_CODE); if (tonAmount) return tonAmount; } const starsAmount = amounts.find((amount) => amount.currency === STARS_CURRENCY_CODE); return starsAmount; } const lang = useLang(); const [isVisible, setIsVisible] = useState(false); const [isHover, markHover, unmarkHover] = useFlag(); const sticker = getStickerFromGift(gift); const isGiftUnique = gift.type === 'starGiftUnique'; const uniqueGift = isGiftUnique ? gift : undefined; const regularGift = !isGiftUnique ? gift : undefined; const priceInfo = !isGiftUnique ? { amount: regularGift?.stars || 0, currency: STARS_CURRENCY_CODE } : getPriceAmount(uniqueGift?.resellPrice); const priceCurrency = priceInfo?.currency || STARS_CURRENCY_CODE; const resellMinStars = regularGift?.resellMinStars; const formattedPrice = !isGiftUnique && isResale && resellMinStars ? lang.number(resellMinStars) + '+' : priceInfo?.amount || 0; const isLimited = !isGiftUnique && Boolean(regularGift?.isLimited); const isSoldOut = !isGiftUnique && Boolean(regularGift?.isSoldOut); const isAuction = !isGiftUnique && !isResale && Boolean(regularGift?.isAuction); const isPremiumRequired = Boolean(gift?.requirePremium); const isUserLimitReached = Boolean(regularGift?.limitedPerUser && !regularGift?.perUserRemains); const perUserTotal = regularGift?.perUserTotal; const handleGiftClick = useLastCallback(() => { if (isAuction) { openGiftAuctionModal({ gift }); return; } if (isSoldOut && !isResale) { openGiftInfoModal({ gift }); return; } if (isUserLimitReached) { showNotification({ message: { key: 'NotificationGiftsLimit2', variables: { count: perUserTotal, }, options: { pluralValue: perUserTotal!, withMarkdown: true, withNodes: true, }, }, }); return; } if (isPremiumRequired && !isCurrentUserPremium) { openPremiumModal({ gift, }); return; } if (isLocked) { checkCanSendGift({ gift, onSuccess: () => onClick?.(gift, isResale ? 'resell' : 'original'), }); return; } onClick?.(gift, isResale ? 'resell' : 'original'); }); const radialPatternBackdrop = useMemo(() => { const { backdrop, pattern } = getGiftAttributes(gift) || {}; if (!backdrop || !pattern) { return undefined; } const backdropColors = [backdrop.centerColor, backdrop.edgeColor]; return ( ); }, [gift]); const giftNumber = isGiftUnique ? gift.number : 0; const isLocked = Boolean(gift.type === 'starGift' && gift.lockedUntilDate); const giftRibbon = useMemo(() => { if (isGiftUnique) { const { backdrop } = getGiftAttributes(gift) || {}; if (!backdrop) { return undefined; } return ( ); } if (isResale) { return ; } if (isSoldOut) { return ; } if (isAuction) { return ; } if (isPremiumRequired) { return ; } if (isLimited) { return ; } return undefined; }, [isGiftUnique, isResale, gift, isSoldOut, isLimited, lang, giftNumber, isPremiumRequired, isAuction]); useOnIntersect(ref, observeIntersection, (entry) => { const visible = entry.isIntersecting; setIsVisible(visible); }); const badgeContent = useMemo(() => { if (withTransferBadge) { return lang('GiftTransferTitle'); } if (isAuction) { return lang('GiftAuctionJoin'); } if (priceCurrency === TON_CURRENCY_CODE) { return formatTonAsIcon(lang, formattedPrice || 0, { shouldConvertFromNanos: true, className: styles.star, }); } return formatStarsAsIcon(lang, formattedPrice || 0, { asFont: true, className: styles.star, }); }, [withTransferBadge, priceCurrency, formattedPrice, isAuction, lang]); return (
{radialPatternBackdrop}
{sticker && ( )}
{!hideBadge && ( )} {giftRibbon} {isLocked && }
); } export default memo( withGlobal((global): Complete => { const isCurrentUserPremium = selectIsCurrentUserPremium(global); return { isCurrentUserPremium, }; })(GiftItemStar), );