From ea2c3111ebfa4c15124e157fb4ae2ee0e861ab65 Mon Sep 17 00:00:00 2001 From: zubiden <19638254+zubiden@users.noreply.github.com> Date: Tue, 21 Jan 2025 18:22:11 +0100 Subject: [PATCH] Unique Gift: Show preview in transactions (#5514) --- .../modals/common/TableInfoModal.module.scss | 2 +- .../modals/gift/UniqueGiftHeader.module.scss | 1 + .../gift/info/GiftInfoModal.module.scss | 36 +--------- .../modals/gift/info/GiftInfoModal.tsx | 67 ++++++------------- .../subscription/StarsSubscriptionItem.tsx | 6 +- .../StarsTransactionItem.module.scss | 14 ++++ .../transaction/StarsTransactionItem.tsx | 48 +++++++++++-- .../StarsTransactionModal.module.scss | 9 ++- .../transaction/StarsTransactionModal.tsx | 31 +++++++-- 9 files changed, 116 insertions(+), 98 deletions(-) diff --git a/src/components/modals/common/TableInfoModal.module.scss b/src/components/modals/common/TableInfoModal.module.scss index 91cd0715f..a04576170 100644 --- a/src/components/modals/common/TableInfoModal.module.scss +++ b/src/components/modals/common/TableInfoModal.module.scss @@ -5,7 +5,7 @@ flex-direction: column; gap: 1rem; padding-inline: 1rem !important; - max-height: min(92vh, 40rem) !important; + max-height: min(92vh, 45rem) !important; overflow-x: hidden; } diff --git a/src/components/modals/gift/UniqueGiftHeader.module.scss b/src/components/modals/gift/UniqueGiftHeader.module.scss index 17fb85bf0..f35b6b6a1 100644 --- a/src/components/modals/gift/UniqueGiftHeader.module.scss +++ b/src/components/modals/gift/UniqueGiftHeader.module.scss @@ -4,6 +4,7 @@ display: flex; flex-direction: column; align-items: center; + width: 100%; height: var(--_height); margin-bottom: 0.5rem; padding-bottom: 1rem; diff --git a/src/components/modals/gift/info/GiftInfoModal.module.scss b/src/components/modals/gift/info/GiftInfoModal.module.scss index 047af6ba8..6c61b02c4 100644 --- a/src/components/modals/gift/info/GiftInfoModal.module.scss +++ b/src/components/modals/gift/info/GiftInfoModal.module.scss @@ -8,18 +8,9 @@ align-items: center; gap: 0.5rem; margin-bottom: 1rem; - position: relative; } -.amount { - display: flex; - gap: 0.25rem; - font-size: 1rem; - font-weight: var(--font-weight-medium); - line-height: 1.325; -} - -.title, .description, .amount { +.title, .description { margin-bottom: 0; } @@ -55,16 +46,6 @@ line-height: 1; } -.radialPattern { - position: absolute; - top: -3rem; - left: -1rem; - right: -1rem; - height: 16.5rem; - - z-index: -1; -} - .uniqueAttribute { display: flex; align-items: center; @@ -72,20 +53,7 @@ } .uniqueGift { - gap: 0; - - .giftSticker { - margin-block: 1rem; - } - - .title { - font-size: 1.25rem; - color: white; - } - - .description { - font-size: 0.875rem; - } + margin-bottom: 0; } .starAmountIcon { diff --git a/src/components/modals/gift/info/GiftInfoModal.tsx b/src/components/modals/gift/info/GiftInfoModal.tsx index b1a52e829..2d5c24156 100644 --- a/src/components/modals/gift/info/GiftInfoModal.tsx +++ b/src/components/modals/gift/info/GiftInfoModal.tsx @@ -10,7 +10,6 @@ import type { TabState } from '../../../../global/types'; import { getUserFullName } from '../../../../global/helpers'; import { selectUser } from '../../../../global/selectors'; import buildClassName from '../../../../util/buildClassName'; -import buildStyle from '../../../../util/buildStyle'; import { formatDateTimeToString } from '../../../../util/dates/dateFormat'; import { formatStarsAsIcon, formatStarsAsText } from '../../../../util/localization/format'; import { CUSTOM_PEER_HIDDEN } from '../../../../util/objects/customPeer'; @@ -28,12 +27,11 @@ import useOldLang from '../../../../hooks/useOldLang'; import AnimatedIconFromSticker from '../../../common/AnimatedIconFromSticker'; import Avatar from '../../../common/Avatar'; import BadgeButton from '../../../common/BadgeButton'; -import StarIcon from '../../../common/icons/StarIcon'; -import RadialPatternBackground from '../../../common/profile/RadialPatternBackground'; import Button from '../../../ui/Button'; import ConfirmDialog from '../../../ui/ConfirmDialog'; import Link from '../../../ui/Link'; import TableInfoModal, { type TableData } from '../../common/TableInfoModal'; +import UniqueGiftHeader from '../UniqueGiftHeader'; import styles from './GiftInfoModal.module.scss'; @@ -117,26 +115,6 @@ const GiftInfoModal = ({ return gift && getGiftAttributes(gift); }, [gift]); - const radialPatternBackdrop = useMemo(() => { - const { backdrop, pattern } = giftAttributes || {}; - - if (!backdrop || !pattern || !isOpen) { - return undefined; - } - - const backdropColors = [backdrop.centerColor, backdrop.edgeColor]; - const patternColor = backdrop.patternColor; - - return ( - - ); - }, [giftAttributes, isOpen]); - const renderFooterButton = useLastCallback(() => { if (canFocusUpgrade) { return ( @@ -173,11 +151,6 @@ const GiftInfoModal = ({ const isVisibleForMe = isNameHidden && targetUser; const description = (() => { - if (gift.type === 'starGiftUnique') { - return lang('GiftInfoCollectible', { - number: gift.number, - }); - } if (!userGift) return lang('GiftInfoSoldOutDescription'); if (userGift.upgradeMsgId) return lang('GiftInfoDescriptionUpgraded'); if (userGift.canUpgrade && userGift.alreadyPaidUpgradeStars) { @@ -240,32 +213,30 @@ const GiftInfoModal = ({ return canUpdate ? lang('GiftInfoReceived') : lang('GiftInfoTitle'); } - const descriptionColor = giftAttributes?.backdrop?.textColor; + const isUniqueGift = gift.type === 'starGiftUnique'; - const header = ( -
- {radialPatternBackdrop} + const uniqueGiftHeader = isUniqueGift && ( +
+ +
+ ); + + const regularHeader = ( +

{getTitle()}

- {gift.type === 'starGift' && ( -

- - {formatInteger(gift.stars)} - - -

- )} {description && (

{description} @@ -487,13 +458,13 @@ const GiftInfoModal = ({ ); return { - header, + header: isUniqueGift ? uniqueGiftHeader : regularHeader, tableData, footer, }; }, [ typeGift, userGift, targetUser, giftSticker, lang, canUpdate, canConvertDifference, isSender, oldLang, gift, - radialPatternBackdrop, giftAttributes, renderFooterButton, + giftAttributes, renderFooterButton, ]); return ( @@ -501,7 +472,7 @@ const GiftInfoModal = ({ { if (!peer) { return undefined; } + const hasExpired = until < Date.now() / 1000; const formattedDate = formatDateToString(until * 1000, lang.code, true, 'long'); @@ -56,11 +58,11 @@ const StarsSubscriptionItem = ({ subscription }: OwnProps) => {

-

{getPeerTitle(lang, peer)}

+

{renderText(getPeerTitle(lang, peer) || '')}

{title && (

{photo && } - {title} + {renderText(title)}

)}

diff --git a/src/components/modals/stars/transaction/StarsTransactionItem.module.scss b/src/components/modals/stars/transaction/StarsTransactionItem.module.scss index 0ef1f1004..59d70670f 100644 --- a/src/components/modals/stars/transaction/StarsTransactionItem.module.scss +++ b/src/components/modals/stars/transaction/StarsTransactionItem.module.scss @@ -68,3 +68,17 @@ @include mixins.filter-outline(1px, var(--color-background)); } + +.uniqueGiftBackground { + position: absolute; + top: 0; + left: 0; + right: 0; + aspect-ratio: 1 / 1; + border-radius: 0.25rem; +} + +.uniqueGift { + margin-inline: 0.25rem; + margin-top: 0.25rem; +} diff --git a/src/components/modals/stars/transaction/StarsTransactionItem.tsx b/src/components/modals/stars/transaction/StarsTransactionItem.tsx index b8256d14c..d7b3cf479 100644 --- a/src/components/modals/stars/transaction/StarsTransactionItem.tsx +++ b/src/components/modals/stars/transaction/StarsTransactionItem.tsx @@ -14,6 +14,7 @@ import { selectPeer } from '../../../../global/selectors'; import buildClassName from '../../../../util/buildClassName'; import { formatDateTimeToString } from '../../../../util/dates/dateFormat'; import { CUSTOM_PEER_PREMIUM } from '../../../../util/objects/customPeer'; +import { getGiftAttributes, getStickerFromGift } from '../../../common/helpers/gifts'; import renderText from '../../../common/helpers/renderText'; import { getTransactionTitle, isNegativeStarsAmount } from '../helpers/transaction'; @@ -22,8 +23,10 @@ import useLang from '../../../../hooks/useLang'; import useLastCallback from '../../../../hooks/useLastCallback'; import useOldLang from '../../../../hooks/useOldLang'; +import AnimatedIconFromSticker from '../../../common/AnimatedIconFromSticker'; import Avatar from '../../../common/Avatar'; import StarIcon from '../../../common/icons/StarIcon'; +import RadialPatternBackground from '../../../common/profile/RadialPatternBackground'; import PaidMediaThumb from './PaidMediaThumb'; import styles from './StarsTransactionItem.module.scss'; @@ -33,6 +36,8 @@ type OwnProps = { className?: string; }; +const UNIQUE_GIFT_STICKER_SIZE = 36; + function selectOptionalPeer(peerId?: string) { return (global: GlobalState) => ( peerId ? selectPeer(global, peerId) : undefined @@ -54,6 +59,8 @@ const StarsTransactionItem = ({ transaction, className }: OwnProps) => { const peerId = transactionPeer.type === 'peer' ? transactionPeer.id : undefined; const peer = useSelector(selectOptionalPeer(peerId)); + const uniqueGift = transaction.starGift?.type === 'starGiftUnique' ? transaction.starGift : undefined; + const uniqueGiftSticker = uniqueGift && getStickerFromGift(uniqueGift); const data = useMemo(() => { let title = getTransactionTitle(oldLang, transaction); @@ -99,6 +106,41 @@ const StarsTransactionItem = ({ transaction, className }: OwnProps) => { }; }, [oldLang, peer, transaction]); + const previewContent = useMemo(() => { + if (uniqueGiftSticker) { + const { backdrop } = getGiftAttributes(uniqueGift)!; + const backgroundColors = [backdrop!.centerColor, backdrop!.edgeColor]; + + return ( + <> + + + + ); + } + + if (extendedMedia) { + return ; + } + + return ( + <> + + {Boolean(subscriptionPeriod) && ( + + )} + + ); + }, [extendedMedia, photo, uniqueGiftSticker, subscriptionPeriod, data.avatarPeer, uniqueGift]); + const handleClick = useLastCallback(() => { openStarsTransactionModal({ transaction }); }); @@ -106,11 +148,7 @@ const StarsTransactionItem = ({ transaction, className }: OwnProps) => { return (

- {extendedMedia ? - : } - {Boolean(subscriptionPeriod) && ( - - )} + {previewContent}

{data.title}

diff --git a/src/components/modals/stars/transaction/StarsTransactionModal.module.scss b/src/components/modals/stars/transaction/StarsTransactionModal.module.scss index 0b5c06bda..5d67f0a63 100644 --- a/src/components/modals/stars/transaction/StarsTransactionModal.module.scss +++ b/src/components/modals/stars/transaction/StarsTransactionModal.module.scss @@ -2,6 +2,10 @@ .modal { z-index: calc(var(--z-modal-low-priority) + 1); + + :global(.modal-dialog) { + overflow: hidden; + } } .positive { @@ -18,7 +22,10 @@ align-items: center; gap: 0.25rem; margin-block: 1rem; - position: relative; +} + +.uniqueGift { + margin-block: 0; } .amount { diff --git a/src/components/modals/stars/transaction/StarsTransactionModal.tsx b/src/components/modals/stars/transaction/StarsTransactionModal.tsx index 7d84f442e..d9bfdb8de 100644 --- a/src/components/modals/stars/transaction/StarsTransactionModal.tsx +++ b/src/components/modals/stars/transaction/StarsTransactionModal.tsx @@ -19,7 +19,7 @@ import { import buildClassName from '../../../../util/buildClassName'; import { copyTextToClipboard } from '../../../../util/clipboard'; import { formatDateTimeToString } from '../../../../util/dates/dateFormat'; -import { getStickerFromGift } from '../../../common/helpers/gifts'; +import { getGiftAttributes, getStickerFromGift } from '../../../common/helpers/gifts'; import { getTransactionTitle, isNegativeStarsAmount } from '../helpers/transaction'; import useLang from '../../../../hooks/useLang'; @@ -33,6 +33,7 @@ import Icon from '../../../common/icons/Icon'; import StarIcon from '../../../common/icons/StarIcon'; import SafeLink from '../../../common/SafeLink'; import TableInfoModal, { type TableData } from '../../common/TableInfoModal'; +import UniqueGiftHeader from '../../gift/UniqueGiftHeader'; import PaidMediaThumb from './PaidMediaThumb'; import styles from './StarsTransactionModal.module.scss'; @@ -58,8 +59,6 @@ const StarsTransactionModal: FC = ({ const oldLang = useOldLang(); const { transaction } = modal || {}; - const sticker = transaction?.starGift ? getStickerFromGift(transaction.starGift) : topSticker; - const handleOpenMedia = useLastCallback(() => { const media = transaction?.extendedMedia; if (!media) return; @@ -79,6 +78,12 @@ const StarsTransactionModal: FC = ({ giveawayPostId, photo, stars, isGiftUpgrade, starGift, } = transaction; + const gift = transaction?.starGift; + const isUniqueGift = gift?.type === 'starGiftUnique'; + const sticker = transaction?.starGift ? getStickerFromGift(transaction.starGift) : topSticker; + + const giftAttributes = isUniqueGift ? getGiftAttributes(gift) : undefined; + const customPeer = (transaction.peer && transaction.peer.type !== 'peer' && buildStarsTransactionCustomPeer(transaction.peer)) || undefined; @@ -108,7 +113,19 @@ const StarsTransactionModal: FC = ({ const shouldDisplayAvatar = !media && !sticker; const avatarPeer = !photo ? (peer || customPeer) : undefined; - const header = ( + const uniqueGiftHeader = isUniqueGift && ( +
+ +
+ ); + + const regularHeader = (
{media && ( = ({ sticker={sticker} play={canPlayAnimatedEmojis} noLoop - nonInteractive /> )} {shouldDisplayAvatar && ( @@ -232,11 +248,11 @@ const StarsTransactionModal: FC = ({ ); return { - header, + header: isUniqueGift ? uniqueGiftHeader : regularHeader, tableData, footer, }; - }, [transaction, oldLang, lang, peer, sticker, canPlayAnimatedEmojis]); + }, [transaction, oldLang, lang, peer, canPlayAnimatedEmojis, topSticker]); const prevModalData = usePrevious(starModalData); const renderingModalData = prevModalData || starModalData; @@ -245,6 +261,7 @@ const StarsTransactionModal: FC = ({