Gifts: Support gift prepaid upgrade (#6415)

This commit is contained in:
Alexander Zinchuk 2025-11-06 11:36:41 +01:00
parent ef5b34229d
commit f8c61646b1
19 changed files with 237 additions and 28 deletions

View File

@ -158,7 +158,7 @@ export function buildApiStarGiftAttribute(attribute: GramJs.TypeStarGiftAttribut
export function buildApiSavedStarGift(userStarGift: GramJs.SavedStarGift, peerId: string): ApiSavedStarGift {
const {
gift, date, convertStars, fromId, message, msgId, nameHidden, unsaved, upgradeStars, transferStars, canUpgrade,
savedId, canExportAt, pinnedToTop, canResellAt, canTransferAt,
savedId, canExportAt, pinnedToTop, canResellAt, canTransferAt, prepaidUpgradeHash,
} = userStarGift;
const inputGift: ApiInputSavedStarGift | undefined = savedId && peerId
@ -183,6 +183,7 @@ export function buildApiSavedStarGift(userStarGift: GramJs.SavedStarGift, peerId
canResellAt,
canTransferAt,
isPinned: pinnedToTop,
prepaidUpgradeHash,
};
}

View File

@ -390,8 +390,8 @@ export function buildApiMessageAction(action: GramJs.TypeMessageAction): ApiMess
}
if (action instanceof GramJs.MessageActionStarGift) {
const {
nameHidden, saved, converted, upgraded, refunded, canUpgrade, gift, message, convertStars, upgradeMsgId,
upgradeStars, fromId, peer, savedId,
nameHidden, saved, converted, upgraded, refunded, canUpgrade, prepaidUpgrade, gift, message, convertStars,
upgradeMsgId, giftMsgId, upgradeStars, fromId, peer, savedId, prepaidUpgradeHash,
} = action;
const starGift = buildApiStarGift(gift);
@ -406,20 +406,23 @@ export function buildApiMessageAction(action: GramJs.TypeMessageAction): ApiMess
isUpgraded: upgraded,
isRefunded: refunded,
canUpgrade,
isPrepaidUpgrade: prepaidUpgrade,
gift: starGift,
message: message && buildApiFormattedText(message),
starsToConvert: toJSNumber(convertStars),
upgradeMsgId,
giftMsgId,
alreadyPaidUpgradeStars: toJSNumber(upgradeStars),
fromId: fromId && getApiChatIdFromMtpPeer(fromId),
peerId: peer && getApiChatIdFromMtpPeer(peer),
savedId: savedId !== undefined ? buildApiPeerId(savedId, 'user') : undefined,
prepaidUpgradeHash,
};
}
if (action instanceof GramJs.MessageActionStarGiftUnique) {
const {
upgrade, transferred, saved, refunded, gift, canExportAt, transferStars, fromId, peer, savedId,
resaleAmount,
resaleAmount, prepaidUpgrade,
} = action;
const starGift = buildApiStarGift(gift);
@ -432,6 +435,7 @@ export function buildApiMessageAction(action: GramJs.TypeMessageAction): ApiMess
isTransferred: transferred,
isSaved: saved,
isRefunded: refunded,
isPrepaidUpgrade: prepaidUpgrade,
gift: starGift,
canExportAt,
transferStars: toJSNumber(transferStars),

View File

@ -553,7 +553,7 @@ export function buildApiStarsTransaction(transaction: GramJs.StarsTransaction):
const {
date, id, peer, amount, description, photo, title, refund, extendedMedia, failed, msgId, pending, gift, reaction,
subscriptionPeriod, stargift, giveawayPostId, starrefCommissionPermille, stargiftUpgrade, paidMessages,
stargiftResale, postsSearch,
stargiftResale, postsSearch, stargiftPrepaidUpgrade,
} = transaction;
if (photo) {
@ -593,6 +593,7 @@ export function buildApiStarsTransaction(transaction: GramJs.StarsTransaction):
isGiftResale: stargiftResale,
paidMessages,
isPostsSearch: postsSearch,
isPrepaidUpgrade: stargiftPrepaidUpgrade,
};
}

View File

@ -781,6 +781,13 @@ export function buildInputInvoice(invoice: ApiRequestInputInvoice) {
});
}
case 'stargiftPrepaidUpgrade': {
return new GramJs.InputInvoiceStarGiftPrepaidUpgrade({
peer: buildInputPeer(invoice.peer.id, invoice.peer.accessHash),
hash: invoice.hash,
});
}
case 'giveaway':
default: {
const purpose = buildInputStorePaymentPurpose(invoice.purpose);

View File

@ -242,14 +242,17 @@ export interface ApiMessageActionStarGift extends ActionMediaType {
isUpgraded?: true;
isRefunded?: true;
canUpgrade?: true;
isPrepaidUpgrade?: true;
gift: ApiStarGiftRegular;
message?: ApiFormattedText;
starsToConvert?: number;
upgradeMsgId?: number;
giftMsgId?: number;
alreadyPaidUpgradeStars?: number;
fromId?: string;
peerId?: string;
savedId?: string;
prepaidUpgradeHash?: string;
}
export interface ApiMessageActionStarGiftUnique extends ActionMediaType {
@ -258,6 +261,7 @@ export interface ApiMessageActionStarGiftUnique extends ActionMediaType {
isTransferred?: true;
isSaved?: true;
isRefunded?: true;
isPrepaidUpgrade?: true;
gift: ApiStarGiftUnique;
canExportAt?: number;
transferStars?: number;

View File

@ -399,10 +399,17 @@ export type ApiInputInvoiceStarGiftTransfer = {
recipientId: string;
};
export type ApiInputInvoiceStarGiftPrepaidUpgrade = {
type: 'stargiftPrepaidUpgrade';
peerId: string;
hash: string;
};
export type ApiInputInvoice = ApiInputInvoiceMessage | ApiInputInvoiceSlug | ApiInputInvoiceGiveaway
| ApiInputInvoiceGiftCode | ApiInputInvoicePremiumGiftStars | ApiInputInvoiceStars | ApiInputInvoiceStarsGift
| ApiInputInvoiceStarsGiveaway | ApiInputInvoiceStarGift | ApiInputInvoiceChatInviteSubscription
| ApiInputInvoiceStarGiftUpgrade | ApiInputInvoiceStarGiftTransfer | ApiInputInvoiceStarGiftResale;
| ApiInputInvoiceStarGiftUpgrade | ApiInputInvoiceStarGiftTransfer | ApiInputInvoiceStarGiftResale
| ApiInputInvoiceStarGiftPrepaidUpgrade;
/* Used for Invoice request */
export type ApiRequestInputInvoiceMessage = {
@ -472,11 +479,18 @@ export type ApiRequestInputInvoiceStarGiftTransfer = {
recipient: ApiPeer;
};
export type ApiRequestInputInvoiceStarGiftPrepaidUpgrade = {
type: 'stargiftPrepaidUpgrade';
peer: ApiPeer;
hash: string;
};
export type ApiRequestInputInvoice = ApiRequestInputInvoiceMessage | ApiRequestInputInvoiceSlug
| ApiRequestInputInvoiceGiveaway | ApiRequestInputInvoiceStars | ApiRequestInputInvoiceStarsGiveaway
| ApiRequestInputInvoiceChatInviteSubscription | ApiRequestInputInvoiceStarGift
| ApiRequestInputInvoiceStarGiftUpgrade | ApiRequestInputInvoiceStarGiftTransfer
| ApiRequestInputInvoicePremiumGiftStars | ApiRequestInputInvoiceStarGiftResale;
| ApiRequestInputInvoicePremiumGiftStars | ApiRequestInputInvoiceStarGiftResale
| ApiRequestInputInvoiceStarGiftPrepaidUpgrade;
export interface ApiUniqueStarGiftValueInfo {
isLastSaleOnFragment?: true;

View File

@ -107,6 +107,7 @@ export interface ApiSavedStarGift {
canTransferAt?: number;
canResellAt?: number;
isPinned?: boolean;
prepaidUpgradeHash?: string;
isConverted?: boolean; // Local field, used for Action Message
upgradeMsgId?: number; // Local field, used for Action Message
localTag?: number; // Local field, used for key in list
@ -244,6 +245,7 @@ export interface ApiStarsTransaction {
isGiftResale?: true;
paidMessages?: number;
isPostsSearch?: true;
isPrepaidUpgrade?: true;
}
export interface ApiStarsSubscription {

View File

@ -1569,8 +1569,14 @@
"GiftUpgradeTextOwn" = "Turn your gift into a unique collectible that you can transfer or auction.";
"GiftUpgradeKeepDetails" = "Keep sender's name and comment";
"GiftUpgradeButton" = "Upgrade for {amount}";
"GiftPayForUpgradeButton" = "Pay {amount} for Upgrade";
"GiftUpgradedTitle" = "This gift is now a collectible";
"GiftUpgradedDescription" = "You have received a unique number, model, backdrop and symbol for your gift.";
"GiftPeerUpgradeUniqueDescription" = "{user} will get a unique number, model, backdrop, and symbol for the gift.";
"GiftPeerUpgradeTransferableDescription" = "{user} will be able to send the gift to anyone on Telegram.";
"GiftPeerUpgradeTradeableDescription" = "{user} will be able to auction the gift on third-party NFT marketplaces.";
"GiftUpgradeSentTitle" = "Gift Upgrade sent!";
"GiftUpgradeSentMessage" = "{user} can now upgrade this gift for free.";
"GiftMakeUnique" = "Make unique for {stars}";
"GiftMakeUniqueAcc" = "Make unique";
"GiftMakeUniqueDescription" = "Enable this to let {user} turn your gift into a unique collectible. {link}";
@ -1872,6 +1878,8 @@
"ActionStarGiftReceivedAnonymous" = "Someone sent you a gift for {cost}";
"ActionStarGiftSentChannel" = "{user} sent a gift to {channel} for {cost}";
"ActionStarGiftSentChannelYou" = "You sent a gift to {channel} for {cost}";
"ActionStarGiftPrepaidUpgradeYou" = "You sent an upgrade worth {cost} for {peer}'s gift";
"ActionStarGiftPrepaidUpgrade" = "{peer} sent an upgrade worth {cost} for your gift";
"ActionStarGiftSelfBought" = "You bought a gift for {cost}";
"ActionStarGiftTo" = "Gift to {peer}";
"ActionStarGiftFrom" = "Gift from {peer}";
@ -2293,6 +2301,10 @@
"TitleGiftLocked" = "Gift Locked";
"GiftLockedMessage" = "This gift is currently only available to earlier Telegram users. It will unlock for your account in about **{relativeDate}**.";
"QuickPreview" = "Quick Preview";
"GiftAnUpgradeButton" = "Gift an Upgrade";
"GiftPrepaidUpgradeTransactionTitle" = "Gift Upgrade";
"ActionStarGiftPrepaidUpgraded" = "{user} turned the gift into a unique collectible";
"ActionStarGiftPrepaidUpgradedYou" = "You turned the gift into a unique collectible";
"UserNoteTitle" = "Notes";
"UserNoteHint" = "only visible to you";
"EditUserNoteHint" = "Notes are only visible to you.";

View File

@ -568,7 +568,7 @@ const ActionMessageText = ({
case 'starGift': {
const {
gift, alreadyPaidUpgradeStars, peerId, savedId, fromId,
gift, alreadyPaidUpgradeStars, peerId, savedId, fromId, isPrepaidUpgrade,
} = action;
const isToChannel = Boolean(peerId && savedId);
@ -576,9 +576,25 @@ const ActionMessageText = ({
const fromTitle = (fromPeer && getPeerTitle(lang, fromPeer)) || userFallbackText;
const fromLink = renderPeerLink(fromPeer?.id, fromTitle, asPreview);
const toPeer = peerId ? selectPeer(global, peerId) : undefined;
const toTitle = (toPeer && getPeerTitle(lang, toPeer))
|| (isToChannel ? channelFallbackText : userFallbackText);
const toLink = renderPeerLink(toPeer?.id, toTitle, asPreview);
const starsAmount = gift.stars + (alreadyPaidUpgradeStars || 0);
const cost = renderStrong(formatStarsAsText(lang, starsAmount));
if (isPrepaidUpgrade && gift.upgradeStars) {
const upgradeCost = renderStrong(formatStarsAsText(lang, gift.upgradeStars));
return translateWithYou(
lang, 'ActionStarGiftPrepaidUpgrade', isOutgoing, {
peer: isOutgoing ? toLink : senderLink,
cost: upgradeCost,
},
);
}
if (isToChannel) {
const channelPeer = selectPeer(global, peerId!);
const isYou = fromPeer?.id === currentUserId;
@ -607,7 +623,7 @@ const ActionMessageText = ({
case 'starGiftUnique': {
const {
isTransferred, isUpgrade, savedId, peerId, fromId, resaleAmount, gift, transferStars,
isTransferred, isUpgrade, savedId, peerId, fromId, resaleAmount, gift, transferStars, isPrepaidUpgrade,
} = action;
const isToChannel = Boolean(peerId && savedId);
@ -616,6 +632,18 @@ const ActionMessageText = ({
const fromTitle = (fromPeer && getPeerTitle(lang, fromPeer)) || userFallbackText;
const fromLink = renderPeerLink(fromPeer?.id, fromTitle, asPreview);
const toPeer = peerId ? selectPeer(global, peerId) : undefined;
const toTitle = (toPeer && getPeerTitle(lang, toPeer))
|| (isToChannel ? channelFallbackText : userFallbackText);
const toLink = renderPeerLink(toPeer?.id, toTitle, asPreview);
if (isPrepaidUpgrade) {
if (isOutgoing) {
return lang('ActionStarGiftPrepaidUpgradedYou');
}
return lang('ActionStarGiftPrepaidUpgraded', { user: toLink }, { withNodes: true });
}
if (resaleAmount && !transferStars) {
const amountText = resaleAmount.currency === TON_CURRENCY_CODE
? formatTonAsText(lang, convertTonFromNanos(resaleAmount.amount))

View File

@ -93,7 +93,7 @@
}
.subtitle {
max-width: 75%;
max-width: 85%;
font-size: 0.875rem;
text-align: center;

View File

@ -282,7 +282,8 @@ const GiftInfoModal = ({
const handleOpenUpgradeModal = useLastCallback(() => {
if (!savedGift) return;
openGiftUpgradeModal({ giftId: savedGift.gift.id, gift: savedGift });
const giftOwnerId = renderingTargetPeer?.id;
openGiftUpgradeModal({ giftId: savedGift.gift.id, gift: savedGift, peerId: giftOwnerId });
});
const handleBuyGift = useLastCallback(() => {
@ -376,6 +377,15 @@ const GiftInfoModal = ({
);
}
if (savedGift?.prepaidUpgradeHash) {
return (
<Button isShiny onClick={handleOpenUpgradeModal}>
{lang('GiftAnUpgradeButton')}
<Icon name="arrow-down-circle" className={styles.upgradeIcon} />
</Button>
);
}
return (
<Button onClick={handleClose}>
{lang('OK')}

View File

@ -49,13 +49,15 @@ type Attributes = {
const PREVIEW_UPDATE_INTERVAL = 3000;
const GiftUpgradeModal = ({ modal, recipient }: OwnProps & StateProps) => {
const { closeGiftUpgradeModal, upgradeGift } = getActions();
const { closeGiftUpgradeModal, closeGiftInfoModal, upgradeGift, upgradePrepaidGift } = getActions();
const isOpen = Boolean(modal);
const renderingModal = useCurrentOrPrev(modal);
const renderingRecipient = useCurrentOrPrev(recipient);
const [shouldKeepOriginalDetails, setShouldKeepOriginalDetails] = useState(false);
const isPrepaid = Boolean(renderingModal?.gift?.prepaidUpgradeHash);
const [previewAttributes, setPreviewAttributes] = useState<Attributes | undefined>();
const lang = useLang();
@ -64,12 +66,31 @@ const GiftUpgradeModal = ({ modal, recipient }: OwnProps & StateProps) => {
const handleUpgrade = useLastCallback(() => {
const gift = renderingModal?.gift;
if (!gift) return;
const regularGift = gift.gift.type === 'starGift' ? gift.gift : undefined;
if (isPrepaid && gift.prepaidUpgradeHash && renderingRecipient) {
const upgradeStars = regularGift?.upgradeStars;
if (!upgradeStars) return;
upgradePrepaidGift({
peerId: renderingRecipient.id,
hash: gift.prepaidUpgradeHash,
stars: upgradeStars,
});
handleClose();
closeGiftInfoModal();
return;
}
if (!gift?.inputGift) return;
upgradeGift({
gift: gift.inputGift,
shouldKeepOriginalDetails,
upgradeStars: !gift.alreadyPaidUpgradeStars ? (gift.gift as ApiStarGiftRegular).upgradeStars : undefined,
upgradeStars: !gift.alreadyPaidUpgradeStars ? regularGift?.upgradeStars : undefined,
});
handleClose();
});
@ -109,16 +130,27 @@ const GiftUpgradeModal = ({ modal, recipient }: OwnProps & StateProps) => {
const gift = renderingModal?.gift;
const listItemData = [
const userName = renderingRecipient ? getPeerTitle(lang, renderingRecipient) : lang('ActionFallbackUser');
const listItemData = (renderingRecipient ? [
['diamond', lang('GiftUpgradeUniqueTitle'), lang('GiftPeerUpgradeUniqueDescription', { user: userName })],
['trade', lang('GiftUpgradeTransferableTitle'),
lang('GiftPeerUpgradeTransferableDescription', { user: userName })],
['auction', lang('GiftUpgradeTradeableTitle'), lang('GiftPeerUpgradeTradeableDescription', { user: userName })],
] : [
['diamond', lang('GiftUpgradeUniqueTitle'), lang('GiftUpgradeUniqueDescription')],
['trade', lang('GiftUpgradeTransferableTitle'), lang('GiftUpgradeTransferableDescription')],
['auction', lang('GiftUpgradeTradeableTitle'), lang('GiftUpgradeTradeableDescription')],
] satisfies TableAboutData;
]) satisfies TableAboutData;
const subtitle = renderingRecipient
? lang('GiftPeerUpgradeText', { peer: getPeerTitle(lang, renderingRecipient) })
: lang('GiftUpgradeTextOwn');
const formattedPrice = gift
? formatStarsAsIcon(lang, (gift.gift as ApiStarGiftRegular).upgradeStars!, { asFont: true })
: undefined;
const header = (
<UniqueGiftHeader
modelAttribute={previewAttributes.model}
@ -138,17 +170,19 @@ const GiftUpgradeModal = ({ modal, recipient }: OwnProps & StateProps) => {
)}
{gift && (
<>
<Checkbox
label={lang('GiftUpgradeKeepDetails')}
onCheck={setShouldKeepOriginalDetails}
checked={shouldKeepOriginalDetails}
/>
{!isPrepaid && (
<Checkbox
label={lang('GiftUpgradeKeepDetails')}
onCheck={setShouldKeepOriginalDetails}
checked={shouldKeepOriginalDetails}
/>
)}
<Button className={styles.footerButton} isShiny onClick={handleUpgrade}>
{gift.alreadyPaidUpgradeStars
? lang('GeneralConfirm')
: lang('GiftUpgradeButton', {
amount: formatStarsAsIcon(lang, (gift.gift as ApiStarGiftRegular).upgradeStars!, { asFont: true }),
}, { withNodes: true })}
: isPrepaid
? lang('GiftPayForUpgradeButton', { amount: formattedPrice }, { withNodes: true })
: lang('GiftUpgradeButton', { amount: formattedPrice }, { withNodes: true })}
</Button>
</>
)}
@ -160,7 +194,9 @@ const GiftUpgradeModal = ({ modal, recipient }: OwnProps & StateProps) => {
header,
footer,
};
}, [previewAttributes, isOpen, lang, renderingRecipient, renderingModal?.gift, shouldKeepOriginalDetails]);
}, [previewAttributes, isOpen, lang,
renderingRecipient, renderingModal?.gift,
shouldKeepOriginalDetails, isPrepaid]);
return (
<TableAboutModal

View File

@ -29,6 +29,10 @@ export function getTransactionTitle(oldLang: OldLangFn, lang: LangFn, transactio
return lang('PostsSearchTransaction');
}
if (transaction.isPrepaidUpgrade) {
return lang('GiftPrepaidUpgradeTransactionTitle');
}
if (transaction.starRefCommision) {
return oldLang('StarTransactionCommission', formatPercent(transaction.starRefCommision));
}

View File

@ -1117,6 +1117,18 @@ addActionHandler('transferGift', (global, actions, payload): ActionReturnType =>
payInputStarInvoice(global, invoice, transferStars, tabId);
});
addActionHandler('upgradePrepaidGift', (global, actions, payload): ActionReturnType => {
const { peerId, hash, stars, tabId = getCurrentTabId() } = payload;
const invoice: ApiInputInvoice = {
type: 'stargiftPrepaidUpgrade',
peerId,
hash,
};
payInputStarInvoice(global, invoice, stars, tabId);
});
async function payInputStarInvoice<T extends GlobalState>(
global: T, inputInvoice: ApiInputInvoice, price: number,
...[tabId = getCurrentTabId()]: TabArgs<T>

View File

@ -2,10 +2,11 @@ import type { ActionReturnType } from '../../types';
import { formatCurrencyAsString } from '../../../util/formatCurrency';
import * as langProvider from '../../../util/oldLangProvider';
import { getPeerTitle } from '../../helpers/peers';
import { addActionHandler, setGlobal } from '../../index';
import { updateStarsBalance } from '../../reducers';
import { updateTabState } from '../../reducers/tabs';
import { selectTabState } from '../../selectors';
import { selectPeer, selectTabState } from '../../selectors';
addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
switch (update['@type']) {
@ -175,6 +176,24 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
actions.reloadPeerSavedGifts({ peerId: global.currentUserId });
}
if (inputInvoice?.type === 'stargiftPrepaidUpgrade') {
actions.reloadPeerSavedGifts({ peerId: inputInvoice.peerId });
const lang = langProvider.getTranslationFn();
const peer = selectPeer(global, inputInvoice.peerId);
const peerTitle = peer ? getPeerTitle(lang, peer) : undefined;
actions.showNotification({
icon: 'gift',
title: { key: 'GiftUpgradeSentTitle' },
message: {
key: 'GiftUpgradeSentMessage',
variables: { user: peerTitle },
},
tabId,
});
}
break;
}

View File

@ -233,12 +233,19 @@ addActionHandler('openGiftInfoModalFromMessage', async (global, actions, payload
const starGift = action.type === 'starGift' ? action : undefined;
const uniqueGift = action.type === 'starGiftUnique' ? action : undefined;
const giftMsgId = starGift?.giftMsgId;
const giftReceiverId = action.peerId || (message.isOutgoing ? message.chatId : global.currentUserId!);
const inputGift: ApiInputSavedStarGift = action.savedId
? { type: 'chat', chatId, savedId: action.savedId }
: { type: 'user', messageId };
const inputGift: ApiInputSavedStarGift = (() => {
if (giftMsgId) {
return { type: 'user', messageId: giftMsgId };
}
if (action.savedId) {
return { type: 'chat', chatId, savedId: action.savedId };
}
return { type: 'user', messageId };
})();
const fromId = action.fromId || (message.isOutgoing ? global.currentUserId! : message.chatId);
@ -259,6 +266,7 @@ addActionHandler('openGiftInfoModalFromMessage', async (global, actions, payload
canExportAt: uniqueGift?.canExportAt,
savedId: action.savedId,
transferStars: uniqueGift?.transferStars,
prepaidUpgradeHash: starGift?.prepaidUpgradeHash,
};
actions.openGiftInfoModal({ peerId: giftReceiverId, gift, tabId });

View File

@ -235,6 +235,18 @@ export function getRequestInputInvoice<T extends GlobalState>(
};
}
if (inputInvoice.type === 'stargiftPrepaidUpgrade') {
const { peerId, hash } = inputInvoice;
const peer = selectPeer(global, peerId);
if (!peer) return undefined;
return {
type: 'stargiftPrepaidUpgrade',
peer,
hash,
};
}
return undefined;
}

View File

@ -2629,6 +2629,11 @@ export interface ActionPayloads {
shouldKeepOriginalDetails?: boolean;
upgradeStars?: number;
} & WithTabId;
upgradePrepaidGift: {
peerId: string;
hash: string;
stars: number;
} & WithTabId;
openGiftWithdrawModal: {
gift: ApiSavedStarGift;

View File

@ -1303,6 +1303,7 @@ export interface LangPair {
'GiftUpgradeKeepDetails': undefined;
'GiftUpgradedTitle': undefined;
'GiftUpgradedDescription': undefined;
'GiftUpgradeSentTitle': undefined;
'GiftMakeUniqueAcc': undefined;
'GiftMakeUniqueLink': undefined;
'GiftWithdrawTitle': undefined;
@ -1716,6 +1717,9 @@ export interface LangPair {
'ConfirmBuyGiftForTonDescription': undefined;
'TitleGiftLocked': undefined;
'QuickPreview': undefined;
'GiftAnUpgradeButton': undefined;
'GiftPrepaidUpgradeTransactionTitle': undefined;
'ActionStarGiftPrepaidUpgradedYou': undefined;
'UserNoteTitle': undefined;
'UserNoteHint': undefined;
'EditUserNoteHint': undefined;
@ -2193,6 +2197,21 @@ export interface LangPairWithVariables<V = LangVariable> {
'GiftUpgradeButton': {
'amount': V;
};
'GiftPayForUpgradeButton': {
'amount': V;
};
'GiftPeerUpgradeUniqueDescription': {
'user': V;
};
'GiftPeerUpgradeTransferableDescription': {
'user': V;
};
'GiftPeerUpgradeTradeableDescription': {
'user': V;
};
'GiftUpgradeSentMessage': {
'user': V;
};
'GiftMakeUnique': {
'stars': V;
};
@ -2486,6 +2505,14 @@ export interface LangPairWithVariables<V = LangVariable> {
'channel': V;
'cost': V;
};
'ActionStarGiftPrepaidUpgradeYou': {
'cost': V;
'peer': V;
};
'ActionStarGiftPrepaidUpgrade': {
'peer': V;
'cost': V;
};
'ActionStarGiftSelfBought': {
'cost': V;
};
@ -2945,6 +2972,9 @@ export interface LangPairWithVariables<V = LangVariable> {
'GiftLockedMessage': {
'relativeDate': V;
};
'ActionStarGiftPrepaidUpgraded': {
'user': V;
};
}
export interface LangPairPlural {