TelegramPWA/src/components/modals/stars/transaction/StarsTransactionItem.tsx
2026-03-31 11:31:16 +02:00

207 lines
6.7 KiB
TypeScript

import { memo, useCallback, useMemo } from '../../../../lib/teact/teact';
import { getActions } from '../../../../global';
import type {
ApiPeer,
ApiStarsTransaction,
} from '../../../../api/types';
import type { GlobalState } from '../../../../global/types';
import type { CustomPeer } from '../../../../types';
import { NNBSP, STARS_CURRENCY_CODE, TON_CURRENCY_CODE } from '../../../../config';
import { buildStarsTransactionCustomPeer,
formatStarsTransactionAmount,
shouldUseCustomPeer } from '../../../../global/helpers/payments';
import { getPeerTitle } from '../../../../global/helpers/peers';
import { selectPeer } from '../../../../global/selectors';
import buildClassName from '../../../../util/buildClassName';
import { formatDateTimeToString } from '../../../../util/dates/oldDateFormat';
import { CUSTOM_PEER_PREMIUM } from '../../../../util/objects/customPeer';
import { getGiftAttributes, getStickerFromGift } from '../../../common/helpers/gifts';
import renderText from '../../../common/helpers/renderText';
import { getTransactionTitle, isNegativeAmount } from '../helpers/transaction';
import useSelector from '../../../../hooks/data/useSelector';
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 Icon from '../../../common/icons/Icon';
import StarIcon from '../../../common/icons/StarIcon';
import RadialPatternBackground from '../../../common/profile/RadialPatternBackground';
import PaidMediaThumb from './PaidMediaThumb';
import styles from './StarsTransactionItem.module.scss';
type OwnProps = {
transaction: ApiStarsTransaction;
className?: string;
};
const GIFT_STICKER_SIZE = 36;
const AVATAR_SIZE = 42;
const StarsTransactionItem = ({ transaction, className }: OwnProps) => {
const { openStarsTransactionModal } = getActions();
const {
date,
amount,
photo,
peer: transactionPeer,
extendedMedia,
subscriptionPeriod,
} = transaction;
const lang = useLang();
const oldLang = useOldLang();
const peerId = transactionPeer.type === 'peer' ? transactionPeer.id : undefined;
const peerSelector = useCallback((global: GlobalState) => {
return peerId ? selectPeer(global, peerId) : undefined;
}, [peerId]);
const peer = useSelector(peerSelector);
const starGift = transaction.starGift;
const isUniqueGift = starGift?.type === 'starGiftUnique';
const giftSticker = starGift && getStickerFromGift(starGift);
const data = useMemo(() => {
let title = getTransactionTitle(oldLang, lang, transaction);
let description;
let status: string | undefined;
let avatarPeer: ApiPeer | CustomPeer | undefined;
if (!shouldUseCustomPeer(transaction)) {
description = peer && getPeerTitle(oldLang, peer);
avatarPeer = peer || CUSTOM_PEER_PREMIUM;
} else {
const customPeer = buildStarsTransactionCustomPeer(transaction);
title = customPeer.title || oldLang(customPeer.titleKey!);
description = oldLang(customPeer.subtitleKey!);
avatarPeer = customPeer;
}
if ((transaction.isGiftUpgrade || transaction.isDropOriginalDetails)
&& transaction.starGift?.type === 'starGiftUnique') {
description = lang('GiftUnique', { title: transaction.starGift.title, number: transaction.starGift.number });
}
if (transaction.isGiftResale && transaction.starGift?.type === 'starGiftUnique') {
description = lang('GiftUnique', { title: transaction.starGift.title, number: transaction.starGift.number });
}
if (transaction.isPostsSearch) {
title = getTransactionTitle(oldLang, lang, transaction);
description = undefined;
}
if (transaction.photo) {
avatarPeer = undefined;
}
if (transaction.isRefund) {
status = oldLang('StarsRefunded');
}
if (transaction.hasFailed) {
status = oldLang('StarsFailed');
}
if (transaction.isPending) {
status = oldLang('StarsPending');
}
return {
title,
description,
avatarPeer,
status,
};
}, [oldLang, lang, peer, transaction]);
const previewContent = useMemo(() => {
if (isUniqueGift) {
const { backdrop } = getGiftAttributes(starGift)!;
const backgroundColors = [backdrop!.centerColor, backdrop!.edgeColor];
return (
<>
<RadialPatternBackground
className={styles.uniqueGiftBackground}
backgroundColors={backgroundColors}
/>
<AnimatedIconFromSticker
className={styles.giftSticker}
sticker={giftSticker}
size={GIFT_STICKER_SIZE}
play={false}
/>
</>
);
}
if (giftSticker) {
return (
<AnimatedIconFromSticker
className={styles.giftSticker}
sticker={giftSticker}
size={GIFT_STICKER_SIZE}
play={false}
/>
);
}
if (extendedMedia) {
return <PaidMediaThumb media={extendedMedia} isTransactionPreview />;
}
return (
<>
<Avatar size={AVATAR_SIZE} webPhoto={photo} peer={data.avatarPeer} />
{Boolean(subscriptionPeriod) && (
<StarIcon className={styles.subscriptionStar} type="gold" size="small" />
)}
</>
);
}, [isUniqueGift, extendedMedia, photo, data.avatarPeer, subscriptionPeriod, starGift, giftSticker]);
const handleClick = useLastCallback(() => {
openStarsTransactionModal({ transaction });
});
const amountColorClass = isNegativeAmount(amount) ? styles.negative : styles.positive;
return (
<div className={buildClassName(styles.root, className)} onClick={handleClick}>
<div className={styles.preview}>
{previewContent}
</div>
<div className={styles.info}>
<h3 className={styles.title}>{data.title}</h3>
{data.description && (
<p className={styles.description}>{renderText(data.description)}</p>
)}
<p className={styles.date}>
{formatDateTimeToString(date * 1000, oldLang.code, true)}
{data.status && ` — (${data.status})`}
</p>
</div>
<span className={styles.stars}>
<span
className={buildClassName(styles.amount, amountColorClass)}
>
{formatStarsTransactionAmount(lang, amount)}
</span>
{NNBSP}
{amount.currency === STARS_CURRENCY_CODE && <StarIcon type="gold" size="adaptive" />}
{amount.currency === TON_CURRENCY_CODE && (
<Icon name="toncoin" className={buildClassName('in-text-icon', amountColorClass)} />
)}
</span>
</div>
);
};
export default memo(StarsTransactionItem);