Unique Gift: Show preview in transactions (#5514)
This commit is contained in:
parent
b8e9dae74f
commit
ea2c3111eb
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: var(--_height);
|
||||
margin-bottom: 0.5rem;
|
||||
padding-bottom: 1rem;
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 (
|
||||
<RadialPatternBackground
|
||||
className={styles.radialPattern}
|
||||
backgroundColors={backdropColors}
|
||||
patternColor={patternColor}
|
||||
patternIcon={pattern.sticker}
|
||||
/>
|
||||
);
|
||||
}, [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 = (
|
||||
<div
|
||||
className={buildClassName(styles.header, radialPatternBackdrop && styles.uniqueGift)}
|
||||
style={buildStyle(descriptionColor && `--_color-description: ${descriptionColor}`)}
|
||||
>
|
||||
{radialPatternBackdrop}
|
||||
const uniqueGiftHeader = isUniqueGift && (
|
||||
<div className={buildClassName(styles.header, styles.uniqueGift)}>
|
||||
<UniqueGiftHeader
|
||||
backdropAttribute={giftAttributes!.backdrop!}
|
||||
patternAttribute={giftAttributes!.pattern!}
|
||||
modelAttribute={giftAttributes!.model!}
|
||||
title={gift.title}
|
||||
subtitle={lang('GiftInfoCollectible', { number: gift.number })}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
const regularHeader = (
|
||||
<div className={styles.header}>
|
||||
<AnimatedIconFromSticker
|
||||
className={styles.giftSticker}
|
||||
sticker={giftSticker}
|
||||
noLoop={false}
|
||||
nonInteractive
|
||||
size={STICKER_SIZE}
|
||||
/>
|
||||
<h1 className={styles.title}>
|
||||
{getTitle()}
|
||||
</h1>
|
||||
{gift.type === 'starGift' && (
|
||||
<p className={styles.amount}>
|
||||
<span className={styles.amount}>
|
||||
{formatInteger(gift.stars)}
|
||||
</span>
|
||||
<StarIcon type="gold" size="middle" />
|
||||
</p>
|
||||
)}
|
||||
{description && (
|
||||
<p className={buildClassName(styles.description, !userGift && gift?.type === 'starGift' && styles.soldOut)}>
|
||||
{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 = ({
|
||||
<TableInfoModal
|
||||
isOpen={isOpen}
|
||||
header={modalData?.header}
|
||||
hasBackdrop={Boolean(radialPatternBackdrop)}
|
||||
hasBackdrop={gift?.type === 'starGiftUnique'}
|
||||
tableData={modalData?.tableData}
|
||||
footer={modalData?.footer}
|
||||
className={styles.modal}
|
||||
|
||||
@ -10,6 +10,7 @@ import { getPeerTitle } from '../../../../global/helpers';
|
||||
import { selectPeer } from '../../../../global/selectors';
|
||||
import { formatDateToString } from '../../../../util/dates/dateFormat';
|
||||
import { formatInteger } from '../../../../util/textFormat';
|
||||
import renderText from '../../../common/helpers/renderText';
|
||||
|
||||
import useSelector from '../../../../hooks/data/useSelector';
|
||||
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||
@ -46,6 +47,7 @@ const StarsSubscriptionItem = ({ subscription }: OwnProps) => {
|
||||
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) => {
|
||||
<StarIcon className={styles.subscriptionStar} type="gold" size="small" />
|
||||
</div>
|
||||
<div className={styles.info}>
|
||||
<h3 className={styles.title}>{getPeerTitle(lang, peer)}</h3>
|
||||
<h3 className={styles.title}>{renderText(getPeerTitle(lang, peer) || '')}</h3>
|
||||
{title && (
|
||||
<p className={styles.subtitle}>
|
||||
{photo && <Avatar webPhoto={photo} size="micro" />}
|
||||
{title}
|
||||
{renderText(title)}
|
||||
</p>
|
||||
)}
|
||||
<p className={styles.description}>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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 (
|
||||
<>
|
||||
<RadialPatternBackground
|
||||
className={styles.uniqueGiftBackground}
|
||||
backgroundColors={backgroundColors}
|
||||
/>
|
||||
<AnimatedIconFromSticker
|
||||
className={styles.uniqueGift}
|
||||
sticker={uniqueGiftSticker}
|
||||
size={UNIQUE_GIFT_STICKER_SIZE}
|
||||
play={false}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (extendedMedia) {
|
||||
return <PaidMediaThumb media={extendedMedia} isTransactionPreview />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Avatar size="medium" webPhoto={photo} peer={data.avatarPeer} />
|
||||
{Boolean(subscriptionPeriod) && (
|
||||
<StarIcon className={styles.subscriptionStar} type="gold" size="small" />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}, [extendedMedia, photo, uniqueGiftSticker, subscriptionPeriod, data.avatarPeer, uniqueGift]);
|
||||
|
||||
const handleClick = useLastCallback(() => {
|
||||
openStarsTransactionModal({ transaction });
|
||||
});
|
||||
@ -106,11 +148,7 @@ const StarsTransactionItem = ({ transaction, className }: OwnProps) => {
|
||||
return (
|
||||
<div className={buildClassName(styles.root, className)} onClick={handleClick}>
|
||||
<div className={styles.preview}>
|
||||
{extendedMedia ? <PaidMediaThumb media={extendedMedia} isTransactionPreview />
|
||||
: <Avatar size="medium" webPhoto={photo} peer={data.avatarPeer} />}
|
||||
{Boolean(subscriptionPeriod) && (
|
||||
<StarIcon className={styles.subscriptionStar} type="gold" size="small" />
|
||||
)}
|
||||
{previewContent}
|
||||
</div>
|
||||
<div className={styles.info}>
|
||||
<h3 className={styles.title}>{data.title}</h3>
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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<OwnProps & StateProps> = ({
|
||||
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<OwnProps & StateProps> = ({
|
||||
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<OwnProps & StateProps> = ({
|
||||
const shouldDisplayAvatar = !media && !sticker;
|
||||
const avatarPeer = !photo ? (peer || customPeer) : undefined;
|
||||
|
||||
const header = (
|
||||
const uniqueGiftHeader = isUniqueGift && (
|
||||
<div className={buildClassName(styles.header, styles.uniqueGift)}>
|
||||
<UniqueGiftHeader
|
||||
backdropAttribute={giftAttributes!.backdrop!}
|
||||
patternAttribute={giftAttributes!.pattern!}
|
||||
modelAttribute={giftAttributes!.model!}
|
||||
title={gift.title}
|
||||
subtitle={lang('GiftInfoCollectible', { number: gift.number })}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
const regularHeader = (
|
||||
<div className={styles.header}>
|
||||
{media && (
|
||||
<PaidMediaThumb
|
||||
@ -123,7 +140,6 @@ const StarsTransactionModal: FC<OwnProps & StateProps> = ({
|
||||
sticker={sticker}
|
||||
play={canPlayAnimatedEmojis}
|
||||
noLoop
|
||||
nonInteractive
|
||||
/>
|
||||
)}
|
||||
{shouldDisplayAvatar && (
|
||||
@ -232,11 +248,11 @@ const StarsTransactionModal: FC<OwnProps & StateProps> = ({
|
||||
);
|
||||
|
||||
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<OwnProps & StateProps> = ({
|
||||
<TableInfoModal
|
||||
isOpen={Boolean(transaction)}
|
||||
className={styles.modal}
|
||||
hasBackdrop={transaction?.starGift?.type === 'starGiftUnique'}
|
||||
header={renderingModalData?.header}
|
||||
tableData={renderingModalData?.tableData}
|
||||
footer={renderingModalData?.footer}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user