Star Gift: Support crafted in readonly mode (#6702)
This commit is contained in:
parent
6c3f009388
commit
ee452ef474
@ -36,7 +36,7 @@ export function buildApiStarGift(starGift: GramJs.TypeStarGift): ApiStarGift {
|
||||
const {
|
||||
id, num, ownerId, ownerName, title, attributes, availabilityIssued, availabilityTotal, slug, ownerAddress,
|
||||
giftAddress, resellAmount, releasedBy, resaleTonOnly, requirePremium, valueCurrency, valueAmount, giftId,
|
||||
valueUsdAmount,
|
||||
valueUsdAmount, burned, crafted,
|
||||
} = starGift;
|
||||
|
||||
return {
|
||||
@ -61,6 +61,8 @@ export function buildApiStarGift(starGift: GramJs.TypeStarGift): ApiStarGift {
|
||||
valueUsdAmount: toJSNumber(valueUsdAmount),
|
||||
regularGiftId: giftId.toString(),
|
||||
offerMinStars: starGift.offerMinStars,
|
||||
isBurned: burned,
|
||||
isCrafted: crafted,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { Api as GramJs } from '../../../lib/gramjs';
|
||||
import { RPCError } from '../../../lib/gramjs/errors';
|
||||
|
||||
import type { GiftProfileFilterOptions, ResaleGiftsFilterOptions } from '../../../types';
|
||||
import type {
|
||||
@ -389,13 +390,22 @@ export async function fetchStarsTopupOptions() {
|
||||
export async function fetchUniqueStarGift({ slug }: {
|
||||
slug: string;
|
||||
}) {
|
||||
const result = await invokeRequest(new GramJs.payments.GetUniqueStarGift({ slug }));
|
||||
try {
|
||||
const result = await invokeRequest(new GramJs.payments.GetUniqueStarGift({ slug }), {
|
||||
shouldThrow: true,
|
||||
});
|
||||
|
||||
if (!result) return undefined;
|
||||
if (!result) return undefined;
|
||||
|
||||
const gift = buildApiStarGift(result.gift);
|
||||
if (gift.type !== 'starGiftUnique') return undefined;
|
||||
return gift;
|
||||
const gift = buildApiStarGift(result.gift);
|
||||
if (gift.type !== 'starGiftUnique') return undefined;
|
||||
return gift;
|
||||
} catch (err) {
|
||||
if (err instanceof RPCError) {
|
||||
return wrapError(err);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchStarGiftUpgradePreview({
|
||||
|
||||
@ -61,6 +61,8 @@ export interface ApiStarGiftUnique {
|
||||
valueAmount?: number;
|
||||
valueUsdAmount?: number;
|
||||
offerMinStars?: number;
|
||||
isBurned?: true;
|
||||
isCrafted?: true;
|
||||
}
|
||||
|
||||
export type ApiStarGift = ApiStarGiftRegular | ApiStarGiftUnique;
|
||||
|
||||
@ -1572,14 +1572,15 @@
|
||||
"GiftInfoOwner" = "Owner";
|
||||
"GiftInfoIssued" = "{issued}/{total} issued";
|
||||
"GiftInfoCollectible" = "Collectible #{number}";
|
||||
"GiftInfoUniqueTitle" = "{name} {number}";
|
||||
"GiftSavedNumber" = "#{number}";
|
||||
"GiftAttributeModel" = "Model";
|
||||
"GiftAttributeBackdrop" = "Backdrop";
|
||||
"GiftAttributeSymbol" = "Symbol";
|
||||
"GiftRarityUncommon" = "Uncommon";
|
||||
"GiftRarityRare" = "Rare";
|
||||
"GiftRarityEpic" = "Epic";
|
||||
"GiftRarityLegendary" = "Legendary";
|
||||
"GiftRarityUncommon" = "uncommon";
|
||||
"GiftRarityRare" = "rare";
|
||||
"GiftRarityEpic" = "epic";
|
||||
"GiftRarityLegendary" = "legendary";
|
||||
"GiftInfoPeerOriginalInfo" = "Gifted to {peer} on {date}.";
|
||||
"GiftInfoPeerOriginalInfoSender" = "Gifted by {sender} to {peer} on {date}.";
|
||||
"GiftInfoPeerOriginalInfoText" = "Gifted to {peer} on {date} with comment \"{text}\".";
|
||||
@ -1923,6 +1924,8 @@
|
||||
"ActionStarGiftTransferredChannelYou" = "You transferred a gift to {channel}";
|
||||
"ActionStarGiftTransferredMine" = "You transferred a gift to {user}";
|
||||
"ActionStarGiftTransferredSelf" = "You transferred a unique collectible";
|
||||
"ActionStarGiftCraftedSelf" = "You crafted a new gift!";
|
||||
"ActionStarGiftCrafted" = "Crafted Gift";
|
||||
"ActionStarGiftTransferredUnknown" = "Someone transferred you a gift";
|
||||
"ActionStarGiftTransferredUnknownChannel" = "Someone transferred a gift to {channel}";
|
||||
"ActionStarGiftSoldFromOffer" = "You sold {gift} to {user} for {cost}";
|
||||
@ -1950,6 +1953,8 @@
|
||||
"ActionStarGiftUnpack" = "Unpack";
|
||||
"ActionStarGiftLimitedRibbon" = "1 of {total}";
|
||||
"ActionStarGiftUniqueRibbon" = "gift";
|
||||
"ActionStarGiftUniqueBurnedRibbon" = "burned";
|
||||
"ActionStarGiftUniqueBurnedError" = "Sorry, this gift has already been burned.";
|
||||
"ActionStarGiftUniqueModel" = "Model";
|
||||
"ActionStarGiftUniqueBackdrop" = "Backdrop";
|
||||
"ActionStarGiftUniqueSymbol" = "Symbol";
|
||||
|
||||
21
src/components/common/GiftRarityBadge.module.scss
Normal file
21
src/components/common/GiftRarityBadge.module.scss
Normal file
@ -0,0 +1,21 @@
|
||||
.root {
|
||||
&.uncommon {
|
||||
color: var(--color-gift-uncommon);
|
||||
background-color: var(--color-gift-uncommon-bg);
|
||||
}
|
||||
|
||||
&.rare {
|
||||
color: var(--color-gift-rare);
|
||||
background-color: var(--color-gift-rare-bg);
|
||||
}
|
||||
|
||||
&.epic {
|
||||
color: var(--color-gift-epic);
|
||||
background-color: var(--color-gift-epic-bg);
|
||||
}
|
||||
|
||||
&.legendary {
|
||||
color: var(--color-gift-legendary);
|
||||
background-color: var(--color-gift-legendary-bg);
|
||||
}
|
||||
}
|
||||
28
src/components/common/GiftRarityBadge.tsx
Normal file
28
src/components/common/GiftRarityBadge.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import { memo } from '../../lib/teact/teact';
|
||||
|
||||
import type { ApiStarGiftAttributeRarity } from '../../api/types';
|
||||
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
import { getGiftRarityTitle } from './helpers/gifts';
|
||||
|
||||
import useLang from '../../hooks/useLang';
|
||||
|
||||
import BadgeButton from './BadgeButton';
|
||||
|
||||
import styles from './GiftRarityBadge.module.scss';
|
||||
|
||||
type OwnProps = {
|
||||
rarity: ApiStarGiftAttributeRarity;
|
||||
};
|
||||
|
||||
const GiftRarityBadge = ({ rarity }: OwnProps) => {
|
||||
const lang = useLang();
|
||||
|
||||
return (
|
||||
<BadgeButton className={buildClassName(styles.root, rarity.type !== 'regular' && styles[rarity.type])}>
|
||||
{getGiftRarityTitle(lang, rarity)}
|
||||
</BadgeButton>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(GiftRarityBadge);
|
||||
@ -158,6 +158,7 @@ const ActionMessage = ({
|
||||
focusMessage,
|
||||
openGiftOfferAcceptModal,
|
||||
declineStarGiftOffer,
|
||||
showNotification,
|
||||
} = getActions();
|
||||
|
||||
const ref = useRef<HTMLDivElement>();
|
||||
@ -371,8 +372,19 @@ const ActionMessage = ({
|
||||
break;
|
||||
}
|
||||
|
||||
case 'starGift':
|
||||
case 'starGift': {
|
||||
openGiftInfoModalFromMessage({
|
||||
chatId: message.chatId,
|
||||
messageId: message.id,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'starGiftUnique': {
|
||||
if (action.gift.isBurned) {
|
||||
showNotification({ message: lang('ActionStarGiftUniqueBurnedError') });
|
||||
break;
|
||||
}
|
||||
openGiftInfoModalFromMessage({
|
||||
chatId: message.chatId,
|
||||
messageId: message.id,
|
||||
|
||||
@ -702,6 +702,7 @@ const ActionMessageText = ({
|
||||
if (isSavedMessages) {
|
||||
if (isUpgrade) return lang('ActionStarGiftUpgradedSelf');
|
||||
if (isTransferred) return lang('ActionStarGiftTransferredSelf');
|
||||
if (gift.isCrafted) return lang('ActionStarGiftCraftedSelf');
|
||||
}
|
||||
|
||||
if (isUpgrade) {
|
||||
|
||||
@ -121,20 +121,24 @@ const StarGiftAction = ({
|
||||
)}
|
||||
</div>
|
||||
<GiftRibbon
|
||||
color={adaptedPatternColor}
|
||||
text={lang('ActionStarGiftUniqueRibbon')}
|
||||
color={action.gift.isBurned ? 'red' : adaptedPatternColor}
|
||||
text={action.gift.isBurned
|
||||
? lang('ActionStarGiftUniqueBurnedRibbon')
|
||||
: lang('ActionStarGiftUniqueRibbon')}
|
||||
/>
|
||||
<div className={styles.info}>
|
||||
<h3 className={styles.title}>
|
||||
{isSelf ? lang('ActionStarGiftSelf') : lang(
|
||||
shouldShowFrom ? 'ActionStarGiftFrom' : 'ActionStarGiftTo',
|
||||
{
|
||||
peer: renderPeerLink(peer?.id, peerTitle || fallbackPeerTitle),
|
||||
},
|
||||
{
|
||||
withNodes: true,
|
||||
},
|
||||
)}
|
||||
{isSelf
|
||||
? (action.gift.isCrafted ? lang('ActionStarGiftCrafted') : lang('ActionStarGiftSelf'))
|
||||
: lang(
|
||||
shouldShowFrom ? 'ActionStarGiftFrom' : 'ActionStarGiftTo',
|
||||
{
|
||||
peer: renderPeerLink(peer?.id, peerTitle || fallbackPeerTitle),
|
||||
},
|
||||
{
|
||||
withNodes: true,
|
||||
},
|
||||
)}
|
||||
</h3>
|
||||
<div className={styles.subtitle} style={`color: ${backdrop.textColor}`}>
|
||||
{lang('GiftUnique', { title: action.gift.title, number: action.gift.number })}
|
||||
|
||||
@ -34,7 +34,7 @@ type OwnProps = {
|
||||
modelAttribute: ApiStarGiftAttributeModel;
|
||||
backdropAttribute: ApiStarGiftAttributeBackdrop;
|
||||
patternAttribute: ApiStarGiftAttributePattern;
|
||||
title?: string;
|
||||
title?: TeactNode;
|
||||
badge?: TeactNode;
|
||||
subtitle?: TeactNode;
|
||||
subtitlePeer?: ApiPeer;
|
||||
@ -114,7 +114,7 @@ const UniqueGiftHeader = ({
|
||||
{Boolean(badge) && (
|
||||
<div className={styles.badge}>{badge}</div>
|
||||
)}
|
||||
{title && <h1 className={styles.title}>{title}</h1>}
|
||||
{Boolean(title) && <h1 className={styles.title}>{title}</h1>}
|
||||
{Boolean(subtitle) && (
|
||||
<div
|
||||
className={buildClassName(styles.subtitle, subtitlePeer && styles.subtitleBadge)}
|
||||
|
||||
@ -2,6 +2,16 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uniqueTitleNumber {
|
||||
&.small {
|
||||
font-size: 0.75em;
|
||||
}
|
||||
|
||||
&.regular {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
}
|
||||
|
||||
.checkBox {
|
||||
margin-inline: -1rem;
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@ import Avatar from '../../../common/Avatar';
|
||||
import BadgeButton from '../../../common/BadgeButton';
|
||||
import GiftMenuItems from '../../../common/gift/GiftMenuItems';
|
||||
import GiftTransferPreview from '../../../common/gift/GiftTransferPreview';
|
||||
import GiftRarityBadge from '../../../common/GiftRarityBadge';
|
||||
import Icon from '../../../common/icons/Icon';
|
||||
import SafeLink from '../../../common/SafeLink';
|
||||
import Button from '../../../ui/Button';
|
||||
@ -182,26 +183,6 @@ const GiftInfoModal = ({
|
||||
const isGiftUnique = gift && gift.type === 'starGiftUnique';
|
||||
const uniqueGift = isGiftUnique ? gift : undefined;
|
||||
|
||||
const giftSubtitle = useMemo(() => {
|
||||
if (!gift || gift.type !== 'starGiftUnique') return undefined;
|
||||
|
||||
if (releasedByPeer) {
|
||||
const releasedByUsername = `@${getMainUsername(releasedByPeer)}`;
|
||||
const ownerTitle = releasedByUsername || getPeerTitle(lang, releasedByPeer);
|
||||
const fallbackText = isApiPeerUser(releasedByPeer)
|
||||
? lang('ActionFallbackUser')
|
||||
: lang('ActionFallbackChannel');
|
||||
|
||||
return lang('GiftInfoCollectibleBy', {
|
||||
number: gift.number, owner: ownerTitle || fallbackText }, {
|
||||
withNodes: true,
|
||||
withMarkdown: true,
|
||||
});
|
||||
}
|
||||
|
||||
return lang('GiftInfoCollectible', { number: gift.number });
|
||||
}, [gift, releasedByPeer, lang]);
|
||||
|
||||
const starGiftUniqueSlug = gift?.type === 'starGiftUnique' ? gift.slug : undefined;
|
||||
|
||||
const selfCollectibleStatus = useMemo(() => {
|
||||
@ -322,6 +303,42 @@ const GiftInfoModal = ({
|
||||
return gift && getGiftAttributes(gift);
|
||||
}, [gift]);
|
||||
|
||||
const uniqueGiftTitle = useMemo(() => {
|
||||
if (!gift || gift.type !== 'starGiftUnique' || !giftAttributes?.backdrop) return undefined;
|
||||
|
||||
const numberColor = giftAttributes.backdrop.textColor;
|
||||
const digitCount = String(gift.number).length;
|
||||
const numberSizeClass = digitCount >= 6 ? styles.small : styles.regular;
|
||||
const styledNumber = (
|
||||
<span className={buildClassName(styles.uniqueTitleNumber, numberSizeClass)} style={`color: ${numberColor}`}>
|
||||
{lang('GiftSavedNumber', { number: gift.number })}
|
||||
</span>
|
||||
);
|
||||
|
||||
return lang('GiftInfoUniqueTitle', {
|
||||
name: gift.title,
|
||||
number: styledNumber,
|
||||
}, { withNodes: true });
|
||||
}, [gift, giftAttributes, lang]);
|
||||
|
||||
const uniqueGiftSubtitle = useMemo(() => {
|
||||
if (!gift || gift.type !== 'starGiftUnique') return undefined;
|
||||
|
||||
if (releasedByPeer) {
|
||||
const releasedByUsername = `@${getMainUsername(releasedByPeer)}`;
|
||||
const ownerTitle = releasedByUsername || getPeerTitle(lang, releasedByPeer);
|
||||
const fallbackText = isApiPeerUser(releasedByPeer)
|
||||
? lang('ActionFallbackUser')
|
||||
: lang('ActionFallbackChannel');
|
||||
|
||||
return ownerTitle || fallbackText;
|
||||
}
|
||||
|
||||
const modelName = giftAttributes?.model?.name;
|
||||
|
||||
return modelName;
|
||||
}, [gift, giftAttributes, releasedByPeer, lang]);
|
||||
|
||||
const renderFooterButton = useLastCallback(() => {
|
||||
if (canBuyGift) {
|
||||
return (
|
||||
@ -551,8 +568,8 @@ const GiftInfoModal = ({
|
||||
backdropAttribute={giftAttributes!.backdrop!}
|
||||
patternAttribute={giftAttributes!.pattern!}
|
||||
modelAttribute={giftAttributes!.model!}
|
||||
title={gift.title}
|
||||
subtitle={giftSubtitle}
|
||||
title={uniqueGiftTitle}
|
||||
subtitle={uniqueGiftSubtitle}
|
||||
subtitlePeer={releasedByPeer}
|
||||
showManageButtons={canManage}
|
||||
savedGift={savedGift}
|
||||
@ -699,7 +716,7 @@ const GiftInfoModal = ({
|
||||
>
|
||||
{model.name}
|
||||
</span>
|
||||
<BadgeButton>{getGiftRarityTitle(lang, model.rarity)}</BadgeButton>
|
||||
<GiftRarityBadge rarity={model.rarity} />
|
||||
</span>,
|
||||
]);
|
||||
}
|
||||
@ -856,8 +873,8 @@ const GiftInfoModal = ({
|
||||
canManage, hasConvertOption, isSender, oldLang, tonExplorerUrl,
|
||||
gift, giftAttributes, renderFooterButton, isTargetChat,
|
||||
isGiftUnique, saleDateInfo,
|
||||
canBuyGift, giftOwnerTitle, resellPrice, giftSubtitle,
|
||||
releasedByPeer, handleSymbolClick, handleBackdropClick, handleModelClick,
|
||||
canBuyGift, giftOwnerTitle, resellPrice, uniqueGiftTitle, uniqueGiftSubtitle, releasedByPeer,
|
||||
handleSymbolClick, handleBackdropClick, handleModelClick,
|
||||
]);
|
||||
|
||||
const moreMenuItems = typeGift && (
|
||||
|
||||
@ -1234,19 +1234,20 @@ addActionHandler('openUniqueGiftBySlug', async (global, actions, payload): Promi
|
||||
slug, tabId = getCurrentTabId(),
|
||||
} = payload;
|
||||
|
||||
const gift = await callApi('fetchUniqueStarGift', { slug });
|
||||
const result = await callApi('fetchUniqueStarGift', { slug });
|
||||
|
||||
if (!gift) {
|
||||
if (!result || 'error' in result) {
|
||||
const isBurned = result && 'error' in result && result.errorMessage === 'STARGIFT_ALREADY_BURNED';
|
||||
actions.showNotification({
|
||||
message: {
|
||||
key: 'GiftWasNotFound',
|
||||
key: isBurned ? 'ActionStarGiftUniqueBurnedError' : 'GiftWasNotFound',
|
||||
},
|
||||
tabId,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
actions.openGiftInfoModal({ gift, tabId });
|
||||
actions.openGiftInfoModal({ gift: result, tabId });
|
||||
});
|
||||
|
||||
addActionHandler('openGiftAuctionBySlug', async (global, actions, payload): Promise<void> => {
|
||||
|
||||
@ -209,6 +209,15 @@ $color-message-story-mention-to: #74bcff;
|
||||
--color-stars: #FFAA00;
|
||||
--color-heart: #ff3c32;
|
||||
|
||||
--color-gift-uncommon: #40A920;
|
||||
--color-gift-uncommon-bg: rgba(64, 169, 32, 0.15);
|
||||
--color-gift-rare: #11AABE;
|
||||
--color-gift-rare-bg: rgba(17, 170, 190, 0.15);
|
||||
--color-gift-epic: #955CDB;
|
||||
--color-gift-epic-bg: rgba(149, 92, 219, 0.15);
|
||||
--color-gift-legendary: #BF7600;
|
||||
--color-gift-legendary-bg: rgba(191, 118, 0, 0.15);
|
||||
|
||||
--color-negative-progress: #CE4C47;
|
||||
|
||||
--vh: 1vh;
|
||||
|
||||
8
src/types/language.d.ts
vendored
8
src/types/language.d.ts
vendored
@ -1521,6 +1521,8 @@ export interface LangPair {
|
||||
'ActionGiftUniqueSent': undefined;
|
||||
'ActionStarGiftUpgradedSelf': undefined;
|
||||
'ActionStarGiftTransferredSelf': undefined;
|
||||
'ActionStarGiftCraftedSelf': undefined;
|
||||
'ActionStarGiftCrafted': undefined;
|
||||
'ActionStarGiftTransferredUnknown': undefined;
|
||||
'ActionStarGiftNoConvertTextYou': undefined;
|
||||
'ActionStarGiftDisplaying': undefined;
|
||||
@ -1529,6 +1531,8 @@ export interface LangPair {
|
||||
'ActionStarGiftUpgraded': undefined;
|
||||
'ActionStarGiftUnpack': undefined;
|
||||
'ActionStarGiftUniqueRibbon': undefined;
|
||||
'ActionStarGiftUniqueBurnedRibbon': undefined;
|
||||
'ActionStarGiftUniqueBurnedError': undefined;
|
||||
'ActionStarGiftUniqueModel': undefined;
|
||||
'ActionStarGiftUniqueBackdrop': undefined;
|
||||
'ActionStarGiftUniqueSymbol': undefined;
|
||||
@ -2377,6 +2381,10 @@ export interface LangPairWithVariables<V = LangVariable> {
|
||||
'GiftInfoCollectible': {
|
||||
'number': V;
|
||||
};
|
||||
'GiftInfoUniqueTitle': {
|
||||
'name': V;
|
||||
'number': V;
|
||||
};
|
||||
'GiftSavedNumber': {
|
||||
'number': V;
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user