diff --git a/src/api/gramjs/apiBuilders/appConfig.ts b/src/api/gramjs/apiBuilders/appConfig.ts index 95492de67..850d20c4c 100644 --- a/src/api/gramjs/apiBuilders/appConfig.ts +++ b/src/api/gramjs/apiBuilders/appConfig.ts @@ -105,6 +105,9 @@ export interface GramJsAppConfig extends LimitsConfig { stars_stargift_resale_amount_max?: number; stars_stargift_resale_amount_min?: number; stars_stargift_resale_commission_permille?: number; + ton_stargift_resale_amount_min?: number; + ton_stargift_resale_amount_max?: number; + ton_stargift_resale_commission_permille?: number; stars_suggested_post_amount_max?: number; stars_suggested_post_amount_min?: number; stars_suggested_post_commission_permille?: number; @@ -225,6 +228,9 @@ export function buildAppConfig(json: GramJs.TypeJSONValue, hash: number): ApiApp starsStargiftResaleAmountMin: appConfig.stars_stargift_resale_amount_min, starsStargiftResaleAmountMax: appConfig.stars_stargift_resale_amount_max, starsStargiftResaleCommissionPermille: appConfig.stars_stargift_resale_commission_permille, + tonStargiftResaleAmountMin: appConfig.ton_stargift_resale_amount_min, + tonStargiftResaleAmountMax: appConfig.ton_stargift_resale_amount_max, + tonStargiftResaleCommissionPermille: appConfig.ton_stargift_resale_commission_permille, starsSuggestedPostAmountMax: appConfig.stars_suggested_post_amount_max, starsSuggestedPostAmountMin: appConfig.stars_suggested_post_amount_min, starsSuggestedPostCommissionPermille: appConfig.stars_suggested_post_commission_permille, diff --git a/src/api/gramjs/apiBuilders/gifts.ts b/src/api/gramjs/apiBuilders/gifts.ts index 35ddb8106..e76166bbf 100644 --- a/src/api/gramjs/apiBuilders/gifts.ts +++ b/src/api/gramjs/apiBuilders/gifts.ts @@ -16,6 +16,7 @@ import { numberToHexColor } from '../../../util/colors'; import { buildApiChatFromPreview } from '../apiBuilders/chats'; import { addDocumentToLocalDb } from '../helpers/localDb'; import { buildApiFormattedText } from './common'; +import { buildApiCurrencyAmount } from './payments'; import { getApiChatIdFromMtpPeer } from './peers'; import { buildStickerFromDocument } from './symbols'; import { buildApiUser } from './users'; @@ -24,7 +25,7 @@ export function buildApiStarGift(starGift: GramJs.TypeStarGift): ApiStarGift { if (starGift instanceof GramJs.StarGiftUnique) { const { id, num, ownerId, ownerName, title, attributes, availabilityIssued, availabilityTotal, slug, ownerAddress, - giftAddress, resellStars, releasedBy, + giftAddress, resellAmount, releasedBy, resaleTonOnly, } = starGift; return { @@ -40,8 +41,9 @@ export function buildApiStarGift(starGift: GramJs.TypeStarGift): ApiStarGift { issuedCount: availabilityIssued, slug, giftAddress, - resellPriceInStars: resellStars?.toJSNumber(), + resellPrice: resellAmount && resellAmount.map((amount) => buildApiCurrencyAmount(amount)).filter(Boolean), releasedByPeerId: releasedBy && getApiChatIdFromMtpPeer(releasedBy), + resaleTonOnly, }; } diff --git a/src/api/gramjs/apiBuilders/messageActions.ts b/src/api/gramjs/apiBuilders/messageActions.ts index 5dc75586e..010df4f83 100644 --- a/src/api/gramjs/apiBuilders/messageActions.ts +++ b/src/api/gramjs/apiBuilders/messageActions.ts @@ -418,7 +418,7 @@ export function buildApiMessageAction(action: GramJs.TypeMessageAction): ApiMess if (action instanceof GramJs.MessageActionStarGiftUnique) { const { upgrade, transferred, saved, refunded, gift, canExportAt, transferStars, fromId, peer, savedId, - resaleStars, + resaleAmount, } = action; const starGift = buildApiStarGift(gift); @@ -437,7 +437,7 @@ export function buildApiMessageAction(action: GramJs.TypeMessageAction): ApiMess fromId: fromId && getApiChatIdFromMtpPeer(fromId), peerId: peer && getApiChatIdFromMtpPeer(peer), savedId: savedId && buildApiPeerId(savedId, 'user'), - resaleStars: resaleStars?.toJSNumber(), + resaleAmount: resaleAmount ? buildApiCurrencyAmount(resaleAmount) : undefined, }; } if (action instanceof GramJs.MessageActionPaidMessagesPrice) { diff --git a/src/api/gramjs/gramjsBuilders/index.ts b/src/api/gramjs/gramjsBuilders/index.ts index 92d4a6745..0f2ca6f51 100644 --- a/src/api/gramjs/gramjsBuilders/index.ts +++ b/src/api/gramjs/gramjsBuilders/index.ts @@ -725,6 +725,7 @@ export function buildInputInvoice(invoice: ApiRequestInputInvoice) { return new GramJs.InputInvoiceStarGiftResale({ toId: buildInputPeer(peer.id, peer.accessHash), slug, + ton: invoice.currency === 'TON' || undefined, }); } diff --git a/src/api/gramjs/methods/stars.ts b/src/api/gramjs/methods/stars.ts index 8eb04d461..5b590e917 100644 --- a/src/api/gramjs/methods/stars.ts +++ b/src/api/gramjs/methods/stars.ts @@ -8,6 +8,7 @@ import type { ApiRequestInputSavedStarGift, ApiStarGiftAttributeId, ApiStarGiftRegular, + ApiTypeCurrencyAmount, } from '../../types'; import { buildApiChatFromPreview } from '../apiBuilders/chats'; @@ -22,7 +23,11 @@ import { buildApiStarTopupOption, } from '../apiBuilders/payments'; import { buildApiUser } from '../apiBuilders/users'; -import { buildInputPeer, buildInputSavedStarGift, buildInputUser, DEFAULT_PRIMITIVES } from '../gramjsBuilders'; +import { buildInputPeer, + buildInputSavedStarGift, + buildInputStarsAmount, + buildInputUser, + DEFAULT_PRIMITIVES } from '../gramjsBuilders'; import { checkErrorType, wrapError } from '../helpers/misc'; import { invokeRequest } from './client'; import { getPassword } from './twoFaSettings'; @@ -423,11 +428,11 @@ export function updateStarGiftPrice({ price, }: { inputSavedGift: ApiRequestInputSavedStarGift; - price: number; + price: ApiTypeCurrencyAmount; }) { return invokeRequest(new GramJs.payments.UpdateStarGiftPrice({ stargift: buildInputSavedStarGift(inputSavedGift), - resellStars: bigInt(price), + resellAmount: buildInputStarsAmount(price), }), { shouldReturnTrue: true, }); diff --git a/src/api/types/messageActions.ts b/src/api/types/messageActions.ts index 333c66242..811abd917 100644 --- a/src/api/types/messageActions.ts +++ b/src/api/types/messageActions.ts @@ -264,7 +264,7 @@ export interface ApiMessageActionStarGiftUnique extends ActionMediaType { fromId?: string; peerId?: string; savedId?: string; - resaleStars?: number; + resaleAmount?: ApiTypeCurrencyAmount; } export interface ApiMessageActionChannelJoined extends ActionMediaType { diff --git a/src/api/types/misc.ts b/src/api/types/misc.ts index 9b318f338..e8df0dfd7 100644 --- a/src/api/types/misc.ts +++ b/src/api/types/misc.ts @@ -261,6 +261,9 @@ export interface ApiAppConfig { tonSuggestedPostCommissionPermille?: number; tonSuggestedPostAmountMax?: number; tonSuggestedPostAmountMin?: number; + tonStargiftResaleAmountMax?: number; + tonStargiftResaleAmountMin?: number; + tonStargiftResaleCommissionPermille?: number; tonUsdRate?: number; tonTopupUrl?: string; pollMaxAnswers?: number; diff --git a/src/api/types/payments.ts b/src/api/types/payments.ts index 143dfd522..dbec67d54 100644 --- a/src/api/types/payments.ts +++ b/src/api/types/payments.ts @@ -1,4 +1,4 @@ -import type { PREMIUM_FEATURE_SECTIONS } from '../../config'; +import type { PREMIUM_FEATURE_SECTIONS, STARS_CURRENCY_CODE, TON_CURRENCY_CODE } from '../../config'; import type { ApiWebDocument } from './bots'; import type { ApiChat, ApiPeer } from './chats'; import type { @@ -364,6 +364,7 @@ export type ApiInputInvoiceStarGiftResale = { type: 'stargiftResale'; slug: string; peerId: string; + currency: typeof TON_CURRENCY_CODE | typeof STARS_CURRENCY_CODE; }; export type ApiInputInvoiceStarsGiveaway = { @@ -451,6 +452,7 @@ export type ApiRequestInputInvoiceStarGiftResale = { type: 'stargiftResale'; slug: string; peer: ApiPeer; + currency: typeof TON_CURRENCY_CODE | typeof STARS_CURRENCY_CODE; }; export type ApiRequestInputInvoiceChatInviteSubscription = { diff --git a/src/api/types/stars.ts b/src/api/types/stars.ts index 67dfeb073..c35414683 100644 --- a/src/api/types/stars.ts +++ b/src/api/types/stars.ts @@ -37,8 +37,9 @@ export interface ApiStarGiftUnique { attributes: ApiStarGiftAttribute[]; slug: string; giftAddress?: string; - resellPriceInStars?: number; + resellPrice?: ApiTypeCurrencyAmount[]; releasedByPeerId?: string; + resaleTonOnly?: true; } export type ApiStarGift = ApiStarGiftRegular | ApiStarGiftUnique; diff --git a/src/assets/localization/fallback.strings b/src/assets/localization/fallback.strings index bd6858368..ef276c22f 100644 --- a/src/assets/localization/fallback.strings +++ b/src/assets/localization/fallback.strings @@ -2152,4 +2152,16 @@ "DescriptionAgeVerificationModal" = "This is a one-time process using your phone's camera. Your selfie will not be stored by Telegram."; "TitleAgeCheckFailed" = "Age Check Failed"; "TitleAgeCheckSuccess" = "Age Check Success"; -"ButtonAgeVerification" = "Verify My Age"; \ No newline at end of file +"ButtonAgeVerification" = "Verify My Age"; +"PriceInStars" = "Price in Stars"; +"PriceInTON" = "Price in TON"; +"DescriptionComposerGiftMinimumCurrencyPrice" = "Minimum price is **{amount}**."; +"DescriptionComposerGiftResaleCurrencyPrice" = "You will receive **{amount}**."; +"ButtonSellGiftTon" = "Sell for {amount}"; +"OnlyAcceptTON" = "Only Accept TON"; +"OnlyAcceptTONDescription" = "If the buyer pays you in TON, there is no risk of refunds, unlike Star payments."; +"DescriptionPayInTON" = "Pay with TON to skip the 21-day wait before transferring the gift again."; +"LabelPayInTON" = "Pay in TON"; +"PriceChanged" = "Price Changed"; +"PayNewPrice" = "Pay New Price"; +"PriceChangedText" = "The price has already changed from **{originalAmount}** to **{newAmount}**. Do you want to pay the new price?"; \ No newline at end of file diff --git a/src/bundles/stars.ts b/src/bundles/stars.ts index e5fc157df..d3eef22fd 100644 --- a/src/bundles/stars.ts +++ b/src/bundles/stars.ts @@ -14,3 +14,4 @@ export { default as GiftStatusInfoModal } from '../components/modals/gift/status export { default as GiftWithdrawModal } from '../components/modals/gift/withdraw/GiftWithdrawModal'; export { default as GiftTransferModal } from '../components/modals/gift/transfer/GiftTransferModal'; export { default as ChatRefundModal } from '../components/modals/stars/chatRefund/ChatRefundModal'; +export { default as PriceConfirmModal } from '../components/modals/priceConfirm/PriceConfirmModal'; diff --git a/src/components/common/gift/GiftMenuItems.tsx b/src/components/common/gift/GiftMenuItems.tsx index 01fa8ddff..24a4ac20d 100644 --- a/src/components/common/gift/GiftMenuItems.tsx +++ b/src/components/common/gift/GiftMenuItems.tsx @@ -69,7 +69,7 @@ const GiftMenuItems = ({ const isGiftUnique = gift && gift.type === 'starGiftUnique'; const canTakeOff = isGiftUnique && currenUniqueEmojiStatusSlug === gift.slug; const canWear = userCollectibleStatus && !canTakeOff; - const giftResalePrice = isGiftUnique ? gift.resellPriceInStars : undefined; + const giftResalePrice = isGiftUnique ? gift.resellPrice : undefined; const hasPinOptions = canManage && savedGift && !savedGift.isUnsaved && isGiftUnique; @@ -124,7 +124,9 @@ const GiftMenuItems = ({ const handleUnsell = useLastCallback(() => { if (!savedGift || savedGift.gift.type !== 'starGiftUnique' || !savedGift.inputGift) return; closeGiftInfoModal(); - updateStarGiftPrice({ gift: savedGift.inputGift, price: 0 }); + updateStarGiftPrice({ gift: savedGift.inputGift, price: { + currency: 'XTR', amount: 0, nanos: 0, + } }); showNotification({ icon: 'unlist-outline', message: { diff --git a/src/components/common/gift/SavedGift.module.scss b/src/components/common/gift/SavedGift.module.scss index 179be0944..39fa978f8 100644 --- a/src/components/common/gift/SavedGift.module.scss +++ b/src/components/common/gift/SavedGift.module.scss @@ -34,6 +34,24 @@ } } +.star { + margin-inline-start: 0 !important; + margin-inline-end: 0.125rem; + font-size: 0.75rem !important; +} + +.priceBadge { + position: absolute; + bottom: 0.5rem; + + height: 1.5rem !important; + margin-top: 0.625rem; + + font-size: 0.6875rem !important; + font-weight: var(--font-weight-semibold) !important; + line-height: 1; +} + .topIcon { position: absolute; top: 0.25rem; diff --git a/src/components/common/gift/SavedGift.tsx b/src/components/common/gift/SavedGift.tsx index 60b93d53f..e90984532 100644 --- a/src/components/common/gift/SavedGift.tsx +++ b/src/components/common/gift/SavedGift.tsx @@ -3,9 +3,11 @@ import { getActions, withGlobal } from '../../../global'; import type { ApiEmojiStatusType, ApiPeer, ApiSavedStarGift } from '../../../api/types'; +import { STARS_CURRENCY_CODE, TON_CURRENCY_CODE } from '../../../config'; import { getHasAdminRight } from '../../../global/helpers'; import { selectChat, selectPeer, selectUser } from '../../../global/selectors'; import buildClassName from '../../../util/buildClassName'; +import { formatStarsAsIcon, formatTonAsIcon } from '../../../util/localization/format'; import { CUSTOM_PEER_HIDDEN } from '../../../util/objects/customPeer'; import { formatIntegerCompact } from '../../../util/textFormat'; import { getGiftAttributes, getStickerFromGift, getTotalGiftAvailability } from '../helpers/gifts'; @@ -16,6 +18,7 @@ import useLang from '../../../hooks/useLang'; import useLastCallback from '../../../hooks/useLastCallback'; import StickerView from '../../common/StickerView'; +import Button from '../../ui/Button'; import Menu from '../../ui/Menu'; import Avatar from '../Avatar'; import Icon from '../icons/Icon'; @@ -66,8 +69,19 @@ const SavedGift = ({ const totalIssued = getTotalGiftAvailability(gift.gift); const starGift = gift.gift; const starGiftUnique = starGift.type === 'starGiftUnique' ? starGift : undefined; + + const resellPrice = useMemo(() => { + if (!starGiftUnique?.resellPrice) return undefined; + + if (starGiftUnique.resaleTonOnly) { + return starGiftUnique.resellPrice.find((amount) => amount.currency === TON_CURRENCY_CODE); + } + + return starGiftUnique.resellPrice.find((amount) => amount.currency === STARS_CURRENCY_CODE); + }, [starGiftUnique]); + const ribbonText = (() => { - if (starGiftUnique?.resellPriceInStars) { + if (starGiftUnique?.resellPrice) { return lang('GiftRibbonSale'); } if (gift.isPinned && starGiftUnique) { @@ -79,7 +93,7 @@ const SavedGift = ({ return undefined; })(); - const ribbonColor = starGiftUnique?.resellPriceInStars ? 'green' : 'blue'; + const ribbonColor = starGiftUnique?.resellPrice ? 'green' : 'blue'; const { isContextMenuOpen, contextMenuAnchor, @@ -161,6 +175,21 @@ const SavedGift = ({ )} + {resellPrice && ( + + )} {ribbonText && ( { const { openChat } = getActions(); const handleOpenChat = useLastCallback((peerId: string) => { @@ -71,6 +73,7 @@ const TableInfoModal = ({ contentClassName={styles.content} onClose={onClose} withBalanceBar={withBalanceBar} + currencyInBalanceBar={currencyInBalanceBar} isLowStackPriority={isLowStackPriority} > {headerAvatarPeer && ( diff --git a/src/components/modals/gift/GiftItemStar.tsx b/src/components/modals/gift/GiftItemStar.tsx index 30f9a4baa..92172ab48 100644 --- a/src/components/modals/gift/GiftItemStar.tsx +++ b/src/components/modals/gift/GiftItemStar.tsx @@ -3,10 +3,12 @@ import { getActions } from '../../../global'; import type { ApiStarGift, + ApiTypeCurrencyAmount, } from '../../../api/types'; +import { STARS_CURRENCY_CODE, TON_CURRENCY_CODE } from '../../../config'; import buildClassName from '../../../util/buildClassName'; -import { formatStarsAsIcon } from '../../../util/localization/format'; +import { formatStarsAsIcon, formatTonAsIcon } from '../../../util/localization/format'; import { getStickerFromGift } from '../../common/helpers/gifts'; import { getGiftAttributes } from '../../common/helpers/gifts'; @@ -38,6 +40,18 @@ function GiftItemStar({ const ref = useRef(); const stickerRef = useRef(); + function getPriceAmount(amounts?: ApiTypeCurrencyAmount[]) { + if (!amounts) return { amount: 0, currency: STARS_CURRENCY_CODE }; + + if (gift.type === 'starGiftUnique' && gift.resaleTonOnly) { + const tonAmount = amounts.find((amount) => amount.currency === TON_CURRENCY_CODE); + if (tonAmount) return tonAmount; + } + + const starsAmount = amounts.find((amount) => amount.currency === STARS_CURRENCY_CODE); + return starsAmount; + } + const lang = useLang(); const [isVisible, setIsVisible] = useState(false); @@ -46,10 +60,13 @@ function GiftItemStar({ const uniqueGift = isGiftUnique ? gift : undefined; const regularGift = !isGiftUnique ? gift : undefined; - const stars = !isGiftUnique ? regularGift?.stars : uniqueGift?.resellPriceInStars; + const priceInfo = !isGiftUnique + ? { amount: regularGift?.stars || 0, currency: STARS_CURRENCY_CODE } + : getPriceAmount(uniqueGift?.resellPrice); + const priceCurrency = priceInfo?.currency || STARS_CURRENCY_CODE; const resellMinStars = regularGift?.resellMinStars; const priceInStarsAsString = !isGiftUnique && isResale && resellMinStars - ? lang.number(resellMinStars) + '+' : stars; + ? lang.number(resellMinStars) + '+' : priceInfo?.amount || 0; const isLimited = !isGiftUnique && Boolean(regularGift?.isLimited); const isSoldOut = !isGiftUnique && Boolean(regularGift?.isSoldOut); @@ -152,7 +169,9 @@ function GiftItemStar({ pill fluid > - {formatStarsAsIcon(lang, priceInStarsAsString || 0, { asFont: true, className: styles.star })} + {priceCurrency === TON_CURRENCY_CODE + ? formatTonAsIcon(lang, priceInStarsAsString || 0, { shouldConvertFromNanos: true, className: styles.star }) + : formatStarsAsIcon(lang, priceInStarsAsString || 0, { asFont: true, className: styles.star })} {giftRibbon} diff --git a/src/components/modals/gift/UniqueGiftHeader.tsx b/src/components/modals/gift/UniqueGiftHeader.tsx index 8bd1302a4..942fdd583 100644 --- a/src/components/modals/gift/UniqueGiftHeader.tsx +++ b/src/components/modals/gift/UniqueGiftHeader.tsx @@ -17,6 +17,7 @@ import { useTransitionActiveKey } from '../../../hooks/animations/useTransitionA import useLang from '../../../hooks/useLang'; import AnimatedIconFromSticker from '../../common/AnimatedIconFromSticker'; +import Icon from '../../common/icons/Icon'; import StarIcon from '../../common/icons/StarIcon'; import RadialPatternBackground from '../../common/profile/RadialPatternBackground'; import Transition from '../../ui/Transition'; @@ -103,7 +104,8 @@ const UniqueGiftHeader = ({ {formatStarsTransactionAmount(lang, resellPrice)} - + {resellPrice.currency === 'XTR' && } + {resellPrice.currency === 'TON' && }

)} diff --git a/src/components/modals/gift/info/GiftInfoModal.module.scss b/src/components/modals/gift/info/GiftInfoModal.module.scss index b749871e2..a997a24eb 100644 --- a/src/components/modals/gift/info/GiftInfoModal.module.scss +++ b/src/components/modals/gift/info/GiftInfoModal.module.scss @@ -2,6 +2,20 @@ overflow: hidden; } +.checkBox { + margin-inline: -1rem; +} + +.checkBoxDescription { + display: flex; + + margin-bottom: 2rem; + margin-inline: 1rem; + + font-size: 0.875rem; + color: var(--color-text-secondary); +} + .header { display: flex; flex-direction: column; diff --git a/src/components/modals/gift/info/GiftInfoModal.tsx b/src/components/modals/gift/info/GiftInfoModal.tsx index c368d5ee9..3acd69da7 100644 --- a/src/components/modals/gift/info/GiftInfoModal.tsx +++ b/src/components/modals/gift/info/GiftInfoModal.tsx @@ -9,6 +9,7 @@ import type { } from '../../../../api/types'; import type { TabState } from '../../../../global/types'; +import { STARS_CURRENCY_CODE, TON_CURRENCY_CODE } from '../../../../config'; import { getHasAdminRight } from '../../../../global/helpers'; import { getPeerTitle, isApiPeerChat, isApiPeerUser } from '../../../../global/helpers/peers'; import { getMainUsername } from '../../../../global/helpers/users'; @@ -16,7 +17,9 @@ import { selectPeer, selectUser } from '../../../../global/selectors'; import buildClassName from '../../../../util/buildClassName'; import { copyTextToClipboard } from '../../../../util/clipboard'; import { formatDateTimeToString } from '../../../../util/dates/dateFormat'; -import { formatStarsAsIcon, formatStarsAsText } from '../../../../util/localization/format'; +import { + formatStarsAsIcon, formatStarsAsText, formatTonAsIcon, formatTonAsText, +} from '../../../../util/localization/format'; import { CUSTOM_PEER_HIDDEN } from '../../../../util/objects/customPeer'; import { getServerTime } from '../../../../util/serverTime'; import { formatPercent } from '../../../../util/textFormat'; @@ -37,6 +40,7 @@ import GiftTransferPreview from '../../../common/gift/GiftTransferPreview'; import Icon from '../../../common/icons/Icon'; import SafeLink from '../../../common/SafeLink'; import Button from '../../../ui/Button'; +import Checkbox from '../../../ui/Checkbox'; import ConfirmDialog from '../../../ui/ConfirmDialog'; import DropdownMenu from '../../../ui/DropdownMenu'; import Link from '../../../ui/Link'; @@ -96,6 +100,7 @@ const GiftInfoModal = ({ const lang = useLang(); const oldLang = useOldLang(); const [isConfirmModalOpen, setIsConfirmModalOpen] = useState(false); + const [shouldPayInTon, setShouldPayInTon] = useState(false); const isOpen = Boolean(modal); const renderingModal = useCurrentOrPrev(modal); @@ -145,8 +150,21 @@ const GiftInfoModal = ({ isTargetChat ? hasAdminRights : renderingTargetPeer?.id === currentUserId ); - const resellPriceInStars = isGiftUnique ? gift.resellPriceInStars : undefined; - const canBuyGift = !canManage && Boolean(resellPriceInStars); + function getResalePrice(shouldPayInTon?: boolean) { + if (!isGiftUnique) return undefined; + const amounts = gift.resellPrice; + if (!amounts) return undefined; + + if (gift?.resaleTonOnly || shouldPayInTon) { + return amounts.find((amount) => amount.currency === TON_CURRENCY_CODE); + } + + return amounts.find((amount) => amount.currency === STARS_CURRENCY_CODE); + } + + const resellPrice = getResalePrice(); + const confirmPrice = getResalePrice(shouldPayInTon); + const canBuyGift = !canManage && Boolean(resellPrice); const giftOwnerTitle = (() => { if (!isGiftUnique) return undefined; @@ -187,7 +205,7 @@ const GiftInfoModal = ({ }); const handleBuyGift = useLastCallback(() => { - if (gift?.type !== 'starGiftUnique' || !gift.resellPriceInStars) return; + if (gift?.type !== 'starGiftUnique' || !getResalePrice()) return; setIsConfirmModalOpen(true); }); @@ -197,10 +215,11 @@ const GiftInfoModal = ({ const handleConfirmBuyGift = useLastCallback(() => { const peer = recipientPeer || currentUser; - if (!peer || gift?.type !== 'starGiftUnique' || !gift.resellPriceInStars) return; + const price = getResalePrice(shouldPayInTon); + if (!peer || !price || gift?.type !== 'starGiftUnique') return; closeConfirmModal(); closeGiftModal(); - buyStarGift({ peerId: peer.id, slug: gift.slug, stars: gift.resellPriceInStars }); + buyStarGift({ peerId: peer.id, slug: gift.slug, price }); }); const giftAttributes = useMemo(() => { @@ -233,7 +252,9 @@ const GiftInfoModal = ({ return ( ); @@ -389,12 +410,17 @@ const GiftInfoModal = ({
- {Boolean(canManage && resellPriceInStars) && ( + {Boolean(canManage && resellPrice) && (
- {formatStarsAsIcon(lang, resellPriceInStars!, { - asFont: true, - className: styles.giftResalePriceStar, - })} + {resellPrice!.currency === TON_CURRENCY_CODE + ? formatTonAsIcon(lang, resellPrice!.amount, { + className: styles.giftResalePriceStar, + shouldConvertFromNanos: true, + }) + : formatStarsAsIcon(lang, resellPrice!.amount, { + asFont: true, + className: styles.giftResalePriceStar, + })}
)}
@@ -727,7 +753,7 @@ const GiftInfoModal = ({ gift, giftAttributes, renderFooterButton, isTargetChat, SettingsMenuButton, isGiftUnique, renderingModal, collectibleEmojiStatuses, currentUserEmojiStatus, saleDateInfo, - canBuyGift, giftOwnerTitle, isOpen, resellPriceInStars, giftSubtitle, + canBuyGift, giftOwnerTitle, isOpen, resellPrice, giftSubtitle, releasedByPeer, ]); @@ -743,15 +769,18 @@ const GiftInfoModal = ({ className={styles.modal} onClose={handleClose} withBalanceBar={Boolean(canBuyGift)} + currencyInBalanceBar={confirmPrice?.currency} isLowStackPriority /> - {uniqueGift && currentUser && Boolean(resellPriceInStars) && ( + {uniqueGift && currentUser && Boolean(confirmPrice) && ( @@ -765,7 +794,9 @@ const GiftInfoModal = ({

{lang('GiftBuyConfirmDescription', { gift: lang('GiftUnique', { title: uniqueGift.title, number: uniqueGift.number }), - stars: formatStarsAsText(lang, resellPriceInStars), + stars: confirmPrice?.currency === TON_CURRENCY_CODE + ? formatTonAsText(lang, confirmPrice.amount, true) + : formatStarsAsText(lang, confirmPrice.amount), }, { withNodes: true, withMarkdown: true, @@ -777,7 +808,9 @@ const GiftInfoModal = ({

{lang('GiftBuyForPeerConfirmDescription', { gift: lang('GiftUnique', { title: uniqueGift.title, number: uniqueGift.number }), - stars: formatStarsAsText(lang, resellPriceInStars), + stars: confirmPrice?.currency === TON_CURRENCY_CODE + ? formatTonAsText(lang, confirmPrice.amount, true) + : formatStarsAsText(lang, confirmPrice.amount), peer: getPeerTitle(lang, recipientPeer), }, { withNodes: true, @@ -785,6 +818,20 @@ const GiftInfoModal = ({ })}

)} + {!uniqueGift.resaleTonOnly && ( + <> + + +
+ {lang('DescriptionPayInTON')} +
+ + )}
)} {savedGift && ( diff --git a/src/components/modals/gift/resale/GiftResalePriceComposerModal.module.scss b/src/components/modals/gift/resale/GiftResalePriceComposerModal.module.scss index e697847d7..c1150d18f 100644 --- a/src/components/modals/gift/resale/GiftResalePriceComposerModal.module.scss +++ b/src/components/modals/gift/resale/GiftResalePriceComposerModal.module.scss @@ -1,4 +1,5 @@ -.descriptionContainer { +.checkBoxDescription, +.inputPriceDescription { display: flex; margin-bottom: 2rem; @@ -8,6 +9,15 @@ color: var(--color-text-secondary); } +.checkBox { + margin-inline: -1rem; +} + +.inputPriceDescription { + margin-top: 0.875rem; + margin-bottom: 1rem; +} + .descriptionPrice { margin-left: auto; } diff --git a/src/components/modals/gift/resale/GiftResalePriceComposerModal.tsx b/src/components/modals/gift/resale/GiftResalePriceComposerModal.tsx index 3a47b6ecc..cc08d8de7 100644 --- a/src/components/modals/gift/resale/GiftResalePriceComposerModal.tsx +++ b/src/components/modals/gift/resale/GiftResalePriceComposerModal.tsx @@ -5,14 +5,17 @@ import { getActions, withGlobal } from '../../../../global'; import type { TabState } from '../../../../global/types'; -import { formatCurrencyAsString } from '../../../../util/formatCurrency'; -import { formatStarsAsIcon, formatStarsAsText } from '../../../../util/localization/format'; +import { convertTonFromNanos, convertTonToNanos } from '../../../../util/formatCurrency'; +import { convertTonToUsd, formatCurrencyAsString } from '../../../../util/formatCurrency'; +import { formatStarsAsIcon, formatStarsAsText, formatTonAsIcon, + formatTonAsText } from '../../../../util/localization/format'; import useCurrentOrPrev from '../../../../hooks/useCurrentOrPrev'; import useLang from '../../../../hooks/useLang'; import useLastCallback from '../../../../hooks/useLastCallback'; import Button from '../../../ui/Button'; +import Checkbox from '../../../ui/Checkbox'; import InputText from '../../../ui/InputText'; import Modal from '../../../ui/Modal'; @@ -27,11 +30,16 @@ export type StateProps = { starsStargiftResaleAmountMin: number; starsStargiftResaleAmountMax?: number; starsUsdWithdrawRate?: number; + tonStargiftResaleCommissionPermille?: number; + tonStargiftResaleAmountMin: number; + tonStargiftResaleAmountMax?: number; + tonUsdRate?: number; }; const GiftResalePriceComposerModal = ({ modal, starsStargiftResaleCommissionPermille, starsStargiftResaleAmountMin, starsStargiftResaleAmountMax, starsUsdWithdrawRate, + tonStargiftResaleCommissionPermille, tonStargiftResaleAmountMin, tonStargiftResaleAmountMax, tonUsdRate, }: OwnProps & StateProps) => { const { closeGiftResalePriceComposerModal, @@ -41,6 +49,7 @@ const GiftResalePriceComposerModal = ({ } = getActions(); const isOpen = Boolean(modal); const [price, setPrice] = useState(undefined); + const [isPriceInTon, setIsPriceInTon] = useState(false); const renderingModal = useCurrentOrPrev(modal); const { gift: typeGift } = renderingModal || {}; @@ -53,8 +62,9 @@ const GiftResalePriceComposerModal = ({ const handleChangePrice = useLastCallback((e) => { const value = e.target.value; const number = parseFloat(value); + const maxAmount = isPriceInTon ? tonStargiftResaleAmountMax : starsStargiftResaleAmountMax; const result = value === '' || Number.isNaN(number) ? undefined - : starsStargiftResaleAmountMax ? Math.min(number, starsStargiftResaleAmountMax) : number; + : maxAmount ? Math.min(number, maxAmount) : number; setPrice(result); }); @@ -66,7 +76,15 @@ const GiftResalePriceComposerModal = ({ if (!savedGift || savedGift.gift.type !== 'starGiftUnique' || !savedGift.inputGift || !price) return; closeGiftResalePriceComposerModal(); closeGiftInfoModal(); - updateStarGiftPrice({ gift: savedGift.inputGift, price }); + updateStarGiftPrice( + { + gift: savedGift.inputGift, + price: { + currency: isPriceInTon ? 'TON' : 'XTR', + amount: isPriceInTon ? convertTonToNanos(price) : price, + nanos: 0, + }, + }); showNotification({ icon: 'sell-outline', message: { @@ -77,50 +95,56 @@ const GiftResalePriceComposerModal = ({ }, }); }); - const commission = starsStargiftResaleCommissionPermille; - const isPriceCorrect = hasPrice && price > starsStargiftResaleAmountMin; + const commission = isPriceInTon ? tonStargiftResaleCommissionPermille : starsStargiftResaleCommissionPermille; + const minAmount = isPriceInTon ? tonStargiftResaleAmountMin : starsStargiftResaleAmountMin; + const isPriceCorrect = hasPrice && price >= minAmount; return (
-
+
{!isPriceCorrect && Boolean(commission) && lang('DescriptionComposerGiftMinimumPrice', { - stars: formatStarsAsText(lang, starsStargiftResaleAmountMin), + stars: isPriceInTon ? formatTonAsText(lang, minAmount) : formatStarsAsText(lang, minAmount), }, { withMarkdown: true, withNodes: true, })} - {isPriceCorrect && lang('DescriptionComposerGiftResalePrice', - { - stars: formatStarsAsText(lang, commission ? Number((price * (commission)).toFixed()) : price), - }, - { - withMarkdown: true, - withNodes: true, - })} + {isPriceCorrect && (() => { + const priceWithCommission = commission ? Number((price * commission).toFixed()) : price; + return lang('DescriptionComposerGiftResalePrice', + { + stars: isPriceInTon + ? formatTonAsText(lang, priceWithCommission) + : formatStarsAsText(lang, priceWithCommission), + }, + { + withMarkdown: true, + withNodes: true, + }); + })()} - {isPriceCorrect && Boolean(starsUsdWithdrawRate) && ( + {isPriceCorrect && Boolean(isPriceInTon ? tonUsdRate : starsUsdWithdrawRate) && ( {`≈ ${formatCurrencyAsString( - price * starsUsdWithdrawRate, + isPriceInTon ? convertTonToUsd(price, tonUsdRate!) : price * starsUsdWithdrawRate!, 'USD', lang.code, )}`} @@ -128,9 +152,21 @@ const GiftResalePriceComposerModal = ({ )}
+ + +
+ {lang('OnlyAcceptTONDescription')} +
+ @@ -148,11 +184,23 @@ export default memo(withGlobal( const starsUsdWithdrawRateX1000 = global.appConfig?.starsUsdWithdrawRateX1000; const starsUsdWithdrawRate = starsUsdWithdrawRateX1000 ? starsUsdWithdrawRateX1000 / 1000 : 1; + const tonConfigPermille = global.appConfig?.tonStargiftResaleCommissionPermille; + const tonStargiftResaleCommissionPermille = tonConfigPermille ? (tonConfigPermille / 1000) : 0; + const tonStargiftResaleAmountMin = convertTonFromNanos(global.appConfig?.tonStargiftResaleAmountMin || 0); + const maxTonFromConfig = global.appConfig?.tonStargiftResaleAmountMax; + const tonStargiftResaleAmountMax = maxTonFromConfig && convertTonFromNanos(maxTonFromConfig); + + const tonUsdRate = global.appConfig?.tonUsdRate; + return { starsStargiftResaleCommissionPermille, starsStargiftResaleAmountMin, starsStargiftResaleAmountMax, starsUsdWithdrawRate, + tonStargiftResaleCommissionPermille, + tonStargiftResaleAmountMin, + tonStargiftResaleAmountMax, + tonUsdRate, }; }, )(GiftResalePriceComposerModal)); diff --git a/src/components/modals/priceConfirm/PriceConfirmModal.async.tsx b/src/components/modals/priceConfirm/PriceConfirmModal.async.tsx new file mode 100644 index 000000000..6b7c37538 --- /dev/null +++ b/src/components/modals/priceConfirm/PriceConfirmModal.async.tsx @@ -0,0 +1,19 @@ +import type { FC } from '../../../lib/teact/teact'; + +import type { TabState } from '../../../global/types'; + +import { Bundles } from '../../../util/moduleLoader'; + +import useModuleLoader from '../../../hooks/useModuleLoader'; + +export type OwnProps = { + modal: TabState['priceConfirmModal']; +}; + +const PriceConfirmModalAsync: FC = ({ modal }) => { + const PriceConfirmModal = useModuleLoader(Bundles.Stars, 'PriceConfirmModal', !modal); + + return PriceConfirmModal ? : undefined; +}; + +export default PriceConfirmModalAsync; diff --git a/src/components/modals/priceConfirm/PriceConfirmModal.tsx b/src/components/modals/priceConfirm/PriceConfirmModal.tsx new file mode 100644 index 000000000..e6703ed86 --- /dev/null +++ b/src/components/modals/priceConfirm/PriceConfirmModal.tsx @@ -0,0 +1,122 @@ +import type { FC } from '../../../lib/teact/teact'; +import { memo, useCallback } from '../../../lib/teact/teact'; +import { getActions, withGlobal } from '../../../global'; + +import type { ApiStarsAmount } from '../../../api/types'; +import type { TabState } from '../../../global/types'; + +import { getCurrentTabId } from '../../../util/establishMultitabRole'; +import { convertTonFromNanos } from '../../../util/formatCurrency'; +import { formatStarsAsText, formatTonAsText } from '../../../util/localization/format'; + +import useLang from '../../../hooks/useLang'; + +import ConfirmDialog from '../../ui/ConfirmDialog'; + +export type OwnProps = { + modal: TabState['priceConfirmModal']; +}; + +type StateProps = { + starBalance?: ApiStarsAmount; + tonBalance?: number; +}; + +const PriceConfirmModal: FC = ({ + modal, + starBalance, + tonBalance, +}) => { + const actions = getActions(); + + const lang = useLang(); + + const handleConfirm = useCallback(() => { + if (!modal?.directInfo) { + actions.closePriceConfirmModal(); + return; + } + + const { currency, newAmount } = modal; + const isTon = currency === 'TON'; + const currentBalance = isTon ? tonBalance : starBalance?.amount; + + if (currentBalance === undefined) { + actions.closePriceConfirmModal(); + return; + } + + if (currentBalance < newAmount!) { + actions.openStarsBalanceModal({ + currency: isTon ? 'TON' : 'XTR', + tabId: getCurrentTabId(), + }); + actions.closePriceConfirmModal(); + return; + } + + actions.sendStarPaymentForm({ + directInfo: modal.directInfo, + tabId: getCurrentTabId(), + }); + actions.closePriceConfirmModal(); + }, [modal, starBalance, tonBalance, actions]); + + const handleClose = useCallback(() => { + actions.closePriceConfirmModal(); + }, [actions]); + + if (!modal) { + return undefined; + } + + const { + originalAmount, + newAmount, + currency, + } = modal; + + const isTon = currency === 'TON'; + + let originalAmountText: string; + let newAmountText: string; + + if (isTon) { + originalAmountText = formatTonAsText(lang, convertTonFromNanos(originalAmount!)); + newAmountText = formatTonAsText(lang, convertTonFromNanos(newAmount!)); + } else { + originalAmountText = formatStarsAsText(lang, originalAmount!); + newAmountText = formatStarsAsText(lang, newAmount!); + } + + return ( + +

+ {lang('PriceChangedText', { + originalAmount: originalAmountText, + newAmount: newAmountText, + }, { + withMarkdown: true, + withNodes: true, + })} +

+
+ ); +}; + +export default memo(withGlobal((global): StateProps => { + const starBalance = global.stars?.balance; + const tonBalance = global.ton?.balance?.amount; + + return { + starBalance, + tonBalance, + }; +}, +)(PriceConfirmModal)); diff --git a/src/components/modals/stars/StarsBalanceModal.module.scss b/src/components/modals/stars/StarsBalanceModal.module.scss index c88670610..e89770cc7 100644 --- a/src/components/modals/stars/StarsBalanceModal.module.scss +++ b/src/components/modals/stars/StarsBalanceModal.module.scss @@ -76,6 +76,12 @@ margin-bottom: 0.5rem; } +.tonBalanceContainer { + display: flex; + flex-direction: column; + justify-content: center; +} + .tonBalance { unicode-bidi: plaintext; display: flex; @@ -87,12 +93,14 @@ } .tonIconBalance { + margin-right: 0.25rem; color: var(--color-primary); } .tonInUsd { font-size: 1rem; color: var(--color-text-secondary); + text-align: center; } .tonIconLogo { diff --git a/src/components/modals/stars/StarsBalanceModal.tsx b/src/components/modals/stars/StarsBalanceModal.tsx index 9ba7a31b1..aba533bc9 100644 --- a/src/components/modals/stars/StarsBalanceModal.tsx +++ b/src/components/modals/stars/StarsBalanceModal.tsx @@ -243,7 +243,7 @@ const StarsBalanceModal = ({ {Boolean(tonUsdRate) && ( {`≈ ${formatCurrencyAsString( - convertTonToUsd(balance?.amount || 0, tonUsdRate), + convertTonToUsd(balance?.amount || 0, tonUsdRate, true), 'USD', lang.code, )}`} diff --git a/src/components/modals/stars/transaction/StarsTransactionItem.tsx b/src/components/modals/stars/transaction/StarsTransactionItem.tsx index e031c7300..6b00d4177 100644 --- a/src/components/modals/stars/transaction/StarsTransactionItem.tsx +++ b/src/components/modals/stars/transaction/StarsTransactionItem.tsx @@ -26,6 +26,7 @@ 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'; @@ -165,6 +166,8 @@ const StarsTransactionItem = ({ transaction, className }: OwnProps) => { openStarsTransactionModal({ transaction }); }); + const amountColorClass = isNegativeAmount(amount) ? styles.negative : styles.positive; + return (
@@ -182,11 +185,12 @@ const StarsTransactionItem = ({ transaction, className }: OwnProps) => {
{formatStarsTransactionAmount(lang, amount)} {amount.currency === STARS_CURRENCY_CODE && } + {amount.currency === TON_CURRENCY_CODE && }
); diff --git a/src/components/modals/stars/transaction/StarsTransactionModal.module.scss b/src/components/modals/stars/transaction/StarsTransactionModal.module.scss index 50152fe7e..fb31737ae 100644 --- a/src/components/modals/stars/transaction/StarsTransactionModal.module.scss +++ b/src/components/modals/stars/transaction/StarsTransactionModal.module.scss @@ -32,6 +32,7 @@ .amount { display: flex; gap: 0.25rem; + align-items: center; font-size: 1rem; font-weight: var(--font-weight-medium); diff --git a/src/components/modals/stars/transaction/StarsTransactionModal.tsx b/src/components/modals/stars/transaction/StarsTransactionModal.tsx index 4b4bc623c..62fe4cbc3 100644 --- a/src/components/modals/stars/transaction/StarsTransactionModal.tsx +++ b/src/components/modals/stars/transaction/StarsTransactionModal.tsx @@ -139,6 +139,8 @@ const StarsTransactionModal: FC = ({
); + const amountColorClass = isNegativeAmount(amount) ? styles.negative : styles.positive; + const regularHeader = (
{media && ( @@ -171,11 +173,12 @@ const StarsTransactionModal: FC = ({

{description}

{formatStarsTransactionAmount(lang, amount)} {amount.currency === STARS_CURRENCY_CODE && } + {amount.currency === 'TON' && } {transaction.isRefund && (

{lang('Refunded')}

)} diff --git a/src/components/modals/suggestMessage/SuggestMessageModal.tsx b/src/components/modals/suggestMessage/SuggestMessageModal.tsx index 1f3ca2664..0e8f7e21f 100644 --- a/src/components/modals/suggestMessage/SuggestMessageModal.tsx +++ b/src/components/modals/suggestMessage/SuggestMessageModal.tsx @@ -290,7 +290,7 @@ const SuggestMessageModal = ({ : currencyAmount ? lang('ButtonOfferAmount', { amount: isCurrencyStars ? formatStarsAsIcon(lang, currencyAmount, { asFont: true }) - : formatTonAsIcon(lang, currencyAmount, { asFont: true }), + : formatTonAsIcon(lang, currencyAmount), }, { withNodes: true, withMarkdown: true, diff --git a/src/components/ui/Modal.tsx b/src/components/ui/Modal.tsx index e5a58732d..5664651fc 100644 --- a/src/components/ui/Modal.tsx +++ b/src/components/ui/Modal.tsx @@ -49,6 +49,7 @@ export type OwnProps = { onCloseAnimationEnd?: () => void; onEnter?: () => void; withBalanceBar?: boolean; + currencyInBalanceBar?: 'TON' | 'XTR'; isCondensedHeader?: boolean; }; @@ -76,6 +77,7 @@ const Modal: FC = ({ onEnter, withBalanceBar, isCondensedHeader, + currencyInBalanceBar = 'XTR', }) => { const { ref: modalRef, @@ -187,6 +189,7 @@ const Modal: FC = ({ {withBalanceBar && ( )}
diff --git a/src/components/ui/ModalStarBalanceBar.module.scss b/src/components/ui/ModalStarBalanceBar.module.scss index 3ef402267..d6753510a 100644 --- a/src/components/ui/ModalStarBalanceBar.module.scss +++ b/src/components/ui/ModalStarBalanceBar.module.scss @@ -43,5 +43,11 @@ } .starIcon { + height: 1rem !important; margin-inline-start: 0.125rem !important; + line-height: 1rem !important; +} + +.tonInUsdDescription { + color: var(--color-text-secondary); } diff --git a/src/components/ui/ModalStarBalanceBar.tsx b/src/components/ui/ModalStarBalanceBar.tsx index d56c6f839..6bc5e4a4d 100644 --- a/src/components/ui/ModalStarBalanceBar.tsx +++ b/src/components/ui/ModalStarBalanceBar.tsx @@ -3,11 +3,15 @@ import { } from '../../lib/teact/teact'; import { getActions, withGlobal } from '../../global'; -import type { ApiStarsAmount } from '../../api/types'; +import type { ApiStarsAmount, ApiTonAmount } from '../../api/types'; +import { + TON_USD_RATE_DEFAULT, +} from '../../config'; import { formatStarsAmount } from '../../global/helpers/payments'; import buildClassName from '../../util/buildClassName'; -import { formatStarsAsIcon } from '../../util/localization/format'; +import { convertTonFromNanos, convertTonToUsd, formatCurrencyAsString } from '../../util/formatCurrency'; +import { formatStarsAsIcon, formatTonAsIcon } from '../../util/localization/format'; import useLang from '../../hooks/useLang'; import useLastCallback from '../../hooks/useLastCallback'; @@ -20,23 +24,31 @@ import styles from './ModalStarBalanceBar.module.scss'; export type OwnProps = { onCloseAnimationEnd?: () => void; isModalOpen?: true; + currency?: 'TON' | 'XTR'; }; export type StateProps = { starBalance?: ApiStarsAmount; + tonBalance?: ApiTonAmount; + tonUsdRate: number; }; function ModalStarBalanceBar({ starBalance, + tonBalance, + tonUsdRate, isModalOpen, onCloseAnimationEnd, + currency, }: StateProps & OwnProps) { const { openStarsBalanceModal, } = getActions(); const lang = useLang(); - const isOpen = isModalOpen ? Boolean(starBalance) : false; + const isTonMode = currency === 'TON'; + const currentBalance = isTonMode ? tonBalance : starBalance; + const isOpen = isModalOpen ? Boolean(currentBalance) : false; const { ref, @@ -48,10 +60,10 @@ function ModalStarBalanceBar({ }); const handleGetMoreStars = useLastCallback(() => { - openStarsBalanceModal({}); + openStarsBalanceModal(isTonMode ? { currency: 'TON' } : {}); }); - if (!shouldRender || !starBalance) { + if (!shouldRender || !currentBalance) { return undefined; } @@ -61,15 +73,41 @@ function ModalStarBalanceBar({ ref={ref} >
- {lang('ModalStarsBalanceBarDescription', { - stars: formatStarsAsIcon(lang, formatStarsAmount(lang, starBalance), { className: styles.starIcon }), - }, { - withNodes: true, - withMarkdown: true, - })} + {isTonMode ? ( + lang('ModalStarsBalanceBarDescription', { + stars: formatTonAsIcon(lang, convertTonFromNanos(currentBalance.amount), { + className: styles.starIcon, + }), + }, { + withNodes: true, + withMarkdown: true, + }) + ) : ( + lang('ModalStarsBalanceBarDescription', { + stars: formatStarsAsIcon(lang, formatStarsAmount(lang, currentBalance as ApiStarsAmount), { + className: styles.starIcon, + }), + }, { + withNodes: true, + withMarkdown: true, + }) + )}
- {lang('GetMoreStarsLinkText')} + {isTonMode && ( +
+ {`≈ ${formatCurrencyAsString( + convertTonToUsd((currentBalance as ApiTonAmount).amount, tonUsdRate, true), + 'USD', + lang.code, + )}`} +
+ )} + {!isTonMode && ( + + {lang('GetMoreStarsLinkText')} + + )}
); @@ -79,10 +117,13 @@ export default memo(withGlobal( (global): StateProps => { const { stars, + ton, } = global; return { starBalance: stars?.balance, + tonBalance: ton?.balance, + tonUsdRate: global.appConfig?.tonUsdRate || TON_USD_RATE_DEFAULT, }; }, )(ModalStarBalanceBar)); diff --git a/src/global/actions/api/payments.ts b/src/global/actions/api/payments.ts index b78102122..e3ed051e1 100644 --- a/src/global/actions/api/payments.ts +++ b/src/global/actions/api/payments.ts @@ -147,16 +147,17 @@ addActionHandler('sendStarGift', (global, actions, payload): ActionReturnType => addActionHandler('buyStarGift', (global, actions, payload): ActionReturnType => { const { - slug, peerId, stars, tabId = getCurrentTabId(), + slug, peerId, price, tabId = getCurrentTabId(), } = payload; const inputInvoice: ApiInputInvoiceStarGiftResale = { type: 'stargiftResale', slug, peerId, + currency: price.currency, }; - payInputStarInvoice(global, inputInvoice, stars, tabId); + payInputStarInvoice(global, inputInvoice, price.amount, tabId); }); addActionHandler('sendPremiumGiftByStars', (global, actions, payload): ActionReturnType => { @@ -1082,12 +1083,13 @@ async function payInputStarInvoice( ...[tabId = getCurrentTabId()]: TabArgs ) { const actions = getActions(); - const balance = global.stars?.balance; + const isTon = inputInvoice.type === 'stargiftResale' && inputInvoice.currency === 'TON'; + const balance = isTon ? global.ton?.balance : global.stars?.balance; if (balance === undefined) return; if (balance.amount < price) { - actions.openStarsBalanceModal({ tabId }); + actions.openStarsBalanceModal({ currency: isTon ? 'TON' : 'XTR', tabId }); return; } @@ -1120,6 +1122,23 @@ async function payInputStarInvoice( return; } + const formPrice = form.invoice.totalAmount; + if (formPrice !== price) { + const isTon = inputInvoice.type === 'stargiftResale' && inputInvoice.currency === 'TON'; + + actions.openPriceConfirmModal({ + originalAmount: price, + newAmount: formPrice, + currency: isTon ? 'TON' : 'XTR', + directInfo: { + inputInvoice, + formId: form.formId, + }, + tabId, + }); + return; + } + actions.sendStarPaymentForm({ directInfo: { inputInvoice, diff --git a/src/global/actions/ui/payments.ts b/src/global/actions/ui/payments.ts index 8336ceda6..9bff3ab6a 100644 --- a/src/global/actions/ui/payments.ts +++ b/src/global/actions/ui/payments.ts @@ -151,3 +151,30 @@ addActionHandler('closePaymentMessageConfirmDialogOpen', (global, actions, paylo isPaymentMessageConfirmDialogOpen: false, }, tabId); }); + +addActionHandler('openPriceConfirmModal', (global, actions, payload): ActionReturnType => { + const { + originalAmount, + newAmount, + currency, + directInfo, + tabId = getCurrentTabId(), + } = payload; + + return updateTabState(global, { + priceConfirmModal: { + originalAmount, + newAmount, + currency, + directInfo, + }, + }, tabId); +}); + +addActionHandler('closePriceConfirmModal', (global, actions, payload): ActionReturnType => { + const { tabId = getCurrentTabId() } = payload || {}; + + return updateTabState(global, { + priceConfirmModal: undefined, + }, tabId); +}); diff --git a/src/global/helpers/payments.ts b/src/global/helpers/payments.ts index 827ddf7c4..4351398a7 100644 --- a/src/global/helpers/payments.ts +++ b/src/global/helpers/payments.ts @@ -16,7 +16,7 @@ import type { GlobalState } from '../types'; import { STARS_CURRENCY_CODE, TON_CURRENCY_CODE } from '../../config'; import arePropsShallowEqual from '../../util/arePropsShallowEqual'; -import { convertCurrencyFromBaseUnit } from '../../util/formatCurrency'; +import { convertTonFromNanos } from '../../util/formatCurrency'; import { selectChat, selectPeer, selectUser } from '../selectors'; export function getRequestInputInvoice( @@ -37,6 +37,7 @@ export function getRequestInputInvoice( type: 'stargiftResale', slug, peer, + currency: inputInvoice.currency, }; } @@ -352,15 +353,14 @@ export function formatStarsTransactionAmount(lang: LangFn, currencyAmount: ApiTy } if (currencyAmount.currency === TON_CURRENCY_CODE) { - const amount = convertCurrencyFromBaseUnit(currencyAmount.amount, currencyAmount.currency); + const amount = convertTonFromNanos(currencyAmount.amount); const absAmount = Math.abs(amount); - const tonText = lang('TonAmountText', { amount: absAmount }, { pluralValue: absAmount }); if (amount < 0) { - return `- ${tonText}`; + return `- ${lang.preciseNumber(absAmount)}`; } - return `+ ${tonText}`; + return `+ ${lang.preciseNumber(absAmount)}`; } return undefined; diff --git a/src/global/types/actions.ts b/src/global/types/actions.ts index ef57f5137..6e05d9c1d 100644 --- a/src/global/types/actions.ts +++ b/src/global/types/actions.ts @@ -2510,7 +2510,7 @@ export interface ActionPayloads { buyStarGift: { peerId: string; slug: string; - stars: number; + price: ApiTypeCurrencyAmount; } & WithTabId; sendPremiumGiftByStars: { userId: string; @@ -2594,7 +2594,7 @@ export interface ActionPayloads { updateStarGiftPrice: { gift: ApiInputSavedStarGift; - price: number; + price: ApiTypeCurrencyAmount; } & WithTabId; openStarsGiftModal: ({ @@ -2638,6 +2638,16 @@ export interface ActionPayloads { openPaymentMessageConfirmDialogOpen: WithTabId | undefined; closePaymentMessageConfirmDialogOpen: WithTabId | undefined; + openPriceConfirmModal: { + originalAmount: number; + newAmount: number; + currency: 'TON' | 'XTR'; + directInfo: { + formId: string; + inputInvoice: ApiInputInvoice; + }; + } & WithTabId; + closePriceConfirmModal: WithTabId | undefined; // Forums toggleForum: { diff --git a/src/global/types/tabState.ts b/src/global/types/tabState.ts index fe9734090..6788453e4 100644 --- a/src/global/types/tabState.ts +++ b/src/global/types/tabState.ts @@ -444,6 +444,16 @@ export type TabState = { status?: ApiPaymentStatus; }; + priceConfirmModal?: { + originalAmount?: number; + newAmount?: number; + currency: 'TON' | 'XTR'; + directInfo?: { + formId: string; + inputInvoice: ApiInputInvoice; + }; + }; + chatCreation?: { progress: ChatCreationProgress; error?: string; diff --git a/src/lib/gramjs/tl/AllTLObjects.ts b/src/lib/gramjs/tl/AllTLObjects.ts index 2c597d0db..aa409c9a7 100644 --- a/src/lib/gramjs/tl/AllTLObjects.ts +++ b/src/lib/gramjs/tl/AllTLObjects.ts @@ -12,6 +12,6 @@ for (const tl of Object.values(Api)) { } } -export const LAYER = 210; +export const LAYER = 211; export { tlobjects }; diff --git a/src/lib/gramjs/tl/api.d.ts b/src/lib/gramjs/tl/api.d.ts index 9875854d0..7da54d461 100644 --- a/src/lib/gramjs/tl/api.d.ts +++ b/src/lib/gramjs/tl/api.d.ts @@ -233,7 +233,7 @@ namespace Api { export type TypeBaseTheme = BaseThemeClassic | BaseThemeDay | BaseThemeNight | BaseThemeTinted | BaseThemeArctic; export type TypeInputThemeSettings = InputThemeSettings; export type TypeThemeSettings = ThemeSettings; - export type TypeWebPageAttribute = WebPageAttributeTheme | WebPageAttributeStory | WebPageAttributeStickerSet | WebPageAttributeUniqueStarGift; + export type TypeWebPageAttribute = WebPageAttributeTheme | WebPageAttributeStory | WebPageAttributeStickerSet | WebPageAttributeUniqueStarGift | WebPageAttributeStarGiftCollection; export type TypeBankCardOpenUrl = BankCardOpenUrl; export type TypeDialogFilter = DialogFilter | DialogFilterDefault | DialogFilterChatlist; export type TypeDialogFilterSuggested = DialogFilterSuggested; @@ -399,6 +399,8 @@ namespace Api { export type TypeSuggestedPost = SuggestedPost; export type TypeStarsRating = StarsRating; export type TypeStarGiftCollection = StarGiftCollection; + export type TypeStoryAlbum = StoryAlbum; + export type TypeSearchPostsFlood = SearchPostsFlood; export type TypeResPQ = ResPQ; export type TypeP_Q_inner_data = PQInnerData | PQInnerDataDc | PQInnerDataTemp | PQInnerDataTempDc; export type TypeServer_DH_Params = ServerDHParamsFail | ServerDHParamsOk; @@ -666,6 +668,7 @@ namespace Api { export type TypeStoryReactionsList = stories.StoryReactionsList; export type TypeFoundStories = stories.FoundStories; export type TypeCanSendStoryCount = stories.CanSendStoryCount; + export type TypeAlbums = stories.AlbumsNotModified | stories.Albums; } export namespace premium { @@ -3238,7 +3241,7 @@ namespace Api { fromId?: Api.TypePeer; peer?: Api.TypePeer; savedId?: long; - resaleStars?: long; + resaleAmount?: Api.TypeStarsAmount; canTransferAt?: int; canResellAt?: int; }> { @@ -3253,10 +3256,10 @@ namespace Api { fromId?: Api.TypePeer; peer?: Api.TypePeer; savedId?: long; - resaleStars?: long; + resaleAmount?: Api.TypeStarsAmount; canTransferAt?: int; canResellAt?: int; - CONSTRUCTOR_ID: 775611918; + CONSTRUCTOR_ID: 888627955; SUBCLASS_OF_ID: 2256589094; className: 'MessageActionStarGiftUnique'; @@ -3922,6 +3925,8 @@ namespace Api { sendPaidMessagesStars?: long; disallowedGifts?: Api.TypeDisallowedGiftsSettings; starsRating?: Api.TypeStarsRating; + starsMyPendingRating?: Api.TypeStarsRating; + starsMyPendingRatingDate?: int; }> { // flags: Api.Type; blocked?: true; @@ -3974,7 +3979,9 @@ namespace Api { sendPaidMessagesStars?: long; disallowedGifts?: Api.TypeDisallowedGiftsSettings; starsRating?: Api.TypeStarsRating; - CONSTRUCTOR_ID: 702447806; + starsMyPendingRating?: Api.TypeStarsRating; + starsMyPendingRatingDate?: int; + CONSTRUCTOR_ID: 2120470047; SUBCLASS_OF_ID: 524706233; className: 'UserFull'; @@ -13040,6 +13047,16 @@ namespace Api { static fromReader(reader: Reader): WebPageAttributeUniqueStarGift; } + export class WebPageAttributeStarGiftCollection extends VirtualClass<{ + icons: Api.TypeDocument[]; + }> { + icons: Api.TypeDocument[]; + CONSTRUCTOR_ID: 835375875; + SUBCLASS_OF_ID: 2949638599; + className: 'WebPageAttributeStarGiftCollection'; + + static fromReader(reader: Reader): WebPageAttributeStarGiftCollection; + } export class BankCardOpenUrl extends VirtualClass<{ url: string; name: string; @@ -14258,12 +14275,16 @@ namespace Api { static fromReader(reader: Reader): InputInvoiceBusinessBotTransferStars; } export class InputInvoiceStarGiftResale extends VirtualClass<{ + // flags: Api.Type; + ton?: true; slug: string; toId: Api.TypeInputPeer; }> { + // flags: Api.Type; + ton?: true; slug: string; toId: Api.TypeInputPeer; - CONSTRUCTOR_ID: 1674298252; + CONSTRUCTOR_ID: 3281998628; SUBCLASS_OF_ID: 1919851518; className: 'InputInvoiceStarGiftResale'; @@ -15176,6 +15197,7 @@ namespace Api { privacy?: Api.TypePrivacyRule[]; views?: Api.TypeStoryViews; sentReaction?: Api.TypeReaction; + albums?: int[]; }> { // flags: Api.Type; pinned?: true; @@ -15199,7 +15221,8 @@ namespace Api { privacy?: Api.TypePrivacyRule[]; views?: Api.TypeStoryViews; sentReaction?: Api.TypeReaction; - CONSTRUCTOR_ID: 2041735716; + albums?: int[]; + CONSTRUCTOR_ID: 3992020209; SUBCLASS_OF_ID: 3564613939; className: 'StoryItem'; @@ -16811,6 +16834,7 @@ namespace Api { export class StarGiftUnique extends VirtualClass<{ // flags: Api.Type; requirePremium?: true; + resaleTonOnly?: true; id: long; title: string; slug: string; @@ -16822,11 +16846,12 @@ namespace Api { availabilityIssued: int; availabilityTotal: int; giftAddress?: string; - resellStars?: long; + resellAmount?: Api.TypeStarsAmount[]; releasedBy?: Api.TypePeer; }> { // flags: Api.Type; requirePremium?: true; + resaleTonOnly?: true; id: long; title: string; slug: string; @@ -16838,9 +16863,9 @@ namespace Api { availabilityIssued: int; availabilityTotal: int; giftAddress?: string; - resellStars?: long; + resellAmount?: Api.TypeStarsAmount[]; releasedBy?: Api.TypePeer; - CONSTRUCTOR_ID: 4130830510; + CONSTRUCTOR_ID: 975654224; SUBCLASS_OF_ID: 3273414923; className: 'StarGiftUnique'; @@ -17437,6 +17462,44 @@ namespace Api { static fromReader(reader: Reader): StarGiftCollection; } + export class StoryAlbum extends VirtualClass<{ + // flags: Api.Type; + albumId: int; + title: string; + iconPhoto?: Api.TypePhoto; + iconVideo?: Api.TypeDocument; + }> { + // flags: Api.Type; + albumId: int; + title: string; + iconPhoto?: Api.TypePhoto; + iconVideo?: Api.TypeDocument; + CONSTRUCTOR_ID: 2468704346; + SUBCLASS_OF_ID: 2089574050; + className: 'StoryAlbum'; + + static fromReader(reader: Reader): StoryAlbum; + } + export class SearchPostsFlood extends VirtualClass<{ + // flags: Api.Type; + queryIsFree?: true; + totalDaily: int; + remains: int; + waitTill?: int; + starsAmount: long; + }> { + // flags: Api.Type; + queryIsFree?: true; + totalDaily: int; + remains: int; + waitTill?: int; + starsAmount: long; + CONSTRUCTOR_ID: 1040931690; + SUBCLASS_OF_ID: 3267415233; + className: 'SearchPostsFlood'; + + static fromReader(reader: Reader): SearchPostsFlood; + } export class ResPQ extends VirtualClass<{ nonce: int128; serverNonce: int128; @@ -18642,6 +18705,7 @@ namespace Api { count: int; nextRate?: int; offsetIdOffset?: int; + searchFlood?: Api.TypeSearchPostsFlood; messages: Api.TypeMessage[]; chats: Api.TypeChat[]; users: Api.TypeUser[]; @@ -18651,10 +18715,11 @@ namespace Api { count: int; nextRate?: int; offsetIdOffset?: int; + searchFlood?: Api.TypeSearchPostsFlood; messages: Api.TypeMessage[]; chats: Api.TypeChat[]; users: Api.TypeUser[]; - CONSTRUCTOR_ID: 978610270; + CONSTRUCTOR_ID: 1982539325; SUBCLASS_OF_ID: 3568569182; className: 'MessagesSlice'; @@ -22042,6 +22107,25 @@ namespace Api { static fromReader(reader: Reader): CanSendStoryCount; } + export class AlbumsNotModified extends VirtualClass { + CONSTRUCTOR_ID: 1448008427; + SUBCLASS_OF_ID: 94846265; + className: 'AlbumsNotModified'; + + static fromReader(reader: Reader): AlbumsNotModified; + } + export class Albums extends VirtualClass<{ + hash: long; + albums: Api.TypeStoryAlbum[]; + }> { + hash: long; + albums: Api.TypeStoryAlbum[]; + CONSTRUCTOR_ID: 3281549882; + SUBCLASS_OF_ID: 94846265; + className: 'Albums'; + + static fromReader(reader: Reader): Albums; + } } export namespace premium { @@ -26582,17 +26666,23 @@ namespace Api { restricted: Bool; } export class SearchPosts extends Request<{ - hashtag: string; + // flags: Api.Type; + hashtag?: string; + query?: string; offsetRate: int; offsetPeer: Api.TypeInputPeer; offsetId: int; limit: int; + allowPaidStars?: long; }, messages.TypeMessages> { - hashtag: string; + // flags: Api.Type; + hashtag?: string; + query?: string; offsetRate: int; offsetPeer: Api.TypeInputPeer; offsetId: int; limit: int; + allowPaidStars?: long; } export class UpdatePaidMessagesPrice extends Request<{ // flags: Api.Type; @@ -26619,6 +26709,13 @@ namespace Api { channel: Api.TypeInputChannel; id: int; } + export class CheckSearchPostsFlood extends Request<{ + // flags: Api.Type; + query?: string; + } | void, Api.TypeSearchPostsFlood> { + // flags: Api.Type; + query?: string; + } } export namespace bots { @@ -27274,10 +27371,10 @@ namespace Api { } export class UpdateStarGiftPrice extends Request<{ stargift: Api.TypeInputSavedStarGift; - resellStars: long; + resellAmount: Api.TypeStarsAmount; }, Api.TypeUpdates> { stargift: Api.TypeInputSavedStarGift; - resellStars: long; + resellAmount: Api.TypeStarsAmount; } export class CreateStarGiftCollection extends Request<{ peer: Api.TypeInputPeer; @@ -28001,6 +28098,7 @@ namespace Api { period?: int; fwdFromId?: Api.TypeInputPeer; fwdFromStory?: int; + albums?: int[]; }, Api.TypeUpdates> { // flags: Api.Type; pinned?: true; @@ -28016,6 +28114,7 @@ namespace Api { period?: int; fwdFromId?: Api.TypeInputPeer; fwdFromStory?: int; + albums?: int[]; } export class EditStory extends Request<{ // flags: Api.Type; @@ -28233,6 +28332,64 @@ namespace Api { offset: string; limit: int; } + export class CreateAlbum extends Request<{ + peer: Api.TypeInputPeer; + title: string; + stories: int[]; + }, Api.TypeStoryAlbum> { + peer: Api.TypeInputPeer; + title: string; + stories: int[]; + } + export class UpdateAlbum extends Request<{ + // flags: Api.Type; + peer: Api.TypeInputPeer; + albumId: int; + title?: string; + deleteStories?: int[]; + addStories?: int[]; + order?: int[]; + }, Api.TypeStoryAlbum> { + // flags: Api.Type; + peer: Api.TypeInputPeer; + albumId: int; + title?: string; + deleteStories?: int[]; + addStories?: int[]; + order?: int[]; + } + export class ReorderAlbums extends Request<{ + peer: Api.TypeInputPeer; + order: int[]; + }, Bool> { + peer: Api.TypeInputPeer; + order: int[]; + } + export class DeleteAlbum extends Request<{ + peer: Api.TypeInputPeer; + albumId: int; + }, Bool> { + peer: Api.TypeInputPeer; + albumId: int; + } + export class GetAlbums extends Request<{ + peer: Api.TypeInputPeer; + hash: long; + }, stories.TypeAlbums> { + peer: Api.TypeInputPeer; + hash: long; + } + export class GetAlbumStories extends Request<{ + peer: Api.TypeInputPeer; + albumId: int; + offset: int; + limit: int; + }, stories.TypeStories> { + peer: Api.TypeInputPeer; + albumId: int; + offset: int; + limit: int; + } } export namespace premium { @@ -28319,7 +28476,7 @@ namespace Api { | photos.UpdateProfilePhoto | photos.UploadProfilePhoto | photos.DeletePhotos | photos.GetUserPhotos | photos.UploadContactProfilePhoto | upload.SaveFilePart | upload.GetFile | upload.SaveBigFilePart | upload.GetWebFile | upload.GetCdnFile | upload.ReuploadCdnFile | upload.GetCdnFileHashes | upload.GetFileHashes | help.GetConfig | help.GetNearestDc | help.GetAppUpdate | help.GetInviteText | help.GetSupport | help.SetBotUpdatesStatus | help.GetCdnConfig | help.GetRecentMeUrls | help.GetTermsOfServiceUpdate | help.AcceptTermsOfService | help.GetDeepLinkInfo | help.GetAppConfig | help.SaveAppLog | help.GetPassportConfig | help.GetSupportName | help.GetUserInfo | help.EditUserInfo | help.GetPromoData | help.HidePromoData | help.DismissSuggestion | help.GetCountriesList | help.GetPremiumPromo | help.GetPeerColors | help.GetPeerProfileColors | help.GetTimezonesList - | channels.ReadHistory | channels.DeleteMessages | channels.ReportSpam | channels.GetMessages | channels.GetParticipants | channels.GetParticipant | channels.GetChannels | channels.GetFullChannel | channels.CreateChannel | channels.EditAdmin | channels.EditTitle | channels.EditPhoto | channels.CheckUsername | channels.UpdateUsername | channels.JoinChannel | channels.LeaveChannel | channels.InviteToChannel | channels.DeleteChannel | channels.ExportMessageLink | channels.ToggleSignatures | channels.GetAdminedPublicChannels | channels.EditBanned | channels.GetAdminLog | channels.SetStickers | channels.ReadMessageContents | channels.DeleteHistory | channels.TogglePreHistoryHidden | channels.GetLeftChannels | channels.GetGroupsForDiscussion | channels.SetDiscussionGroup | channels.EditCreator | channels.EditLocation | channels.ToggleSlowMode | channels.GetInactiveChannels | channels.ConvertToGigagroup | channels.GetSendAs | channels.DeleteParticipantHistory | channels.ToggleJoinToSend | channels.ToggleJoinRequest | channels.ReorderUsernames | channels.ToggleUsername | channels.DeactivateAllUsernames | channels.ToggleForum | channels.CreateForumTopic | channels.GetForumTopics | channels.GetForumTopicsByID | channels.EditForumTopic | channels.UpdatePinnedForumTopic | channels.DeleteTopicHistory | channels.ReorderPinnedForumTopics | channels.ToggleAntiSpam | channels.ReportAntiSpamFalsePositive | channels.ToggleParticipantsHidden | channels.UpdateColor | channels.ToggleViewForumAsMessages | channels.GetChannelRecommendations | channels.UpdateEmojiStatus | channels.SetBoostsToUnblockRestrictions | channels.SetEmojiStickers | channels.RestrictSponsoredMessages | channels.SearchPosts | channels.UpdatePaidMessagesPrice | channels.ToggleAutotranslation | channels.GetMessageAuthor + | channels.ReadHistory | channels.DeleteMessages | channels.ReportSpam | channels.GetMessages | channels.GetParticipants | channels.GetParticipant | channels.GetChannels | channels.GetFullChannel | channels.CreateChannel | channels.EditAdmin | channels.EditTitle | channels.EditPhoto | channels.CheckUsername | channels.UpdateUsername | channels.JoinChannel | channels.LeaveChannel | channels.InviteToChannel | channels.DeleteChannel | channels.ExportMessageLink | channels.ToggleSignatures | channels.GetAdminedPublicChannels | channels.EditBanned | channels.GetAdminLog | channels.SetStickers | channels.ReadMessageContents | channels.DeleteHistory | channels.TogglePreHistoryHidden | channels.GetLeftChannels | channels.GetGroupsForDiscussion | channels.SetDiscussionGroup | channels.EditCreator | channels.EditLocation | channels.ToggleSlowMode | channels.GetInactiveChannels | channels.ConvertToGigagroup | channels.GetSendAs | channels.DeleteParticipantHistory | channels.ToggleJoinToSend | channels.ToggleJoinRequest | channels.ReorderUsernames | channels.ToggleUsername | channels.DeactivateAllUsernames | channels.ToggleForum | channels.CreateForumTopic | channels.GetForumTopics | channels.GetForumTopicsByID | channels.EditForumTopic | channels.UpdatePinnedForumTopic | channels.DeleteTopicHistory | channels.ReorderPinnedForumTopics | channels.ToggleAntiSpam | channels.ReportAntiSpamFalsePositive | channels.ToggleParticipantsHidden | channels.UpdateColor | channels.ToggleViewForumAsMessages | channels.GetChannelRecommendations | channels.UpdateEmojiStatus | channels.SetBoostsToUnblockRestrictions | channels.SetEmojiStickers | channels.RestrictSponsoredMessages | channels.SearchPosts | channels.UpdatePaidMessagesPrice | channels.ToggleAutotranslation | channels.GetMessageAuthor | channels.CheckSearchPostsFlood | bots.SendCustomRequest | bots.AnswerWebhookJSONQuery | bots.SetBotCommands | bots.ResetBotCommands | bots.GetBotCommands | bots.SetBotMenuButton | bots.GetBotMenuButton | bots.SetBotBroadcastDefaultAdminRights | bots.SetBotGroupDefaultAdminRights | bots.SetBotInfo | bots.GetBotInfo | bots.ReorderUsernames | bots.ToggleUsername | bots.CanSendMessage | bots.AllowSendMessage | bots.InvokeWebViewCustomMethod | bots.GetPopularAppBots | bots.AddPreviewMedia | bots.EditPreviewMedia | bots.DeletePreviewMedia | bots.ReorderPreviewMedias | bots.GetPreviewInfo | bots.GetPreviewMedias | bots.UpdateUserEmojiStatus | bots.ToggleUserEmojiStatusPermission | bots.CheckDownloadFileParams | bots.GetAdminedBots | bots.UpdateStarRefProgram | bots.SetCustomVerification | bots.GetBotRecommendations | payments.GetPaymentForm | payments.GetPaymentReceipt | payments.ValidateRequestedInfo | payments.SendPaymentForm | payments.GetSavedInfo | payments.ClearSavedInfo | payments.GetBankCardData | payments.ExportInvoice | payments.AssignAppStoreTransaction | payments.AssignPlayMarketTransaction | payments.GetPremiumGiftCodeOptions | payments.CheckGiftCode | payments.ApplyGiftCode | payments.GetGiveawayInfo | payments.LaunchPrepaidGiveaway | payments.GetStarsTopupOptions | payments.GetStarsStatus | payments.GetStarsTransactions | payments.SendStarsForm | payments.RefundStarsCharge | payments.GetStarsRevenueStats | payments.GetStarsRevenueWithdrawalUrl | payments.GetStarsRevenueAdsAccountUrl | payments.GetStarsTransactionsByID | payments.GetStarsGiftOptions | payments.GetStarsSubscriptions | payments.ChangeStarsSubscription | payments.FulfillStarsSubscription | payments.GetStarsGiveawayOptions | payments.GetStarGifts | payments.SaveStarGift | payments.ConvertStarGift | payments.BotCancelStarsSubscription | payments.GetConnectedStarRefBots | payments.GetConnectedStarRefBot | payments.GetSuggestedStarRefBots | payments.ConnectStarRefBot | payments.EditConnectedStarRefBot | payments.GetStarGiftUpgradePreview | payments.UpgradeStarGift | payments.TransferStarGift | payments.GetUniqueStarGift | payments.GetSavedStarGifts | payments.GetSavedStarGift | payments.GetStarGiftWithdrawalUrl | payments.ToggleChatStarGiftNotifications | payments.ToggleStarGiftsPinnedToTop | payments.CanPurchaseStore | payments.GetResaleStarGifts | payments.UpdateStarGiftPrice | payments.CreateStarGiftCollection | payments.UpdateStarGiftCollection | payments.ReorderStarGiftCollections | payments.DeleteStarGiftCollection | payments.GetStarGiftCollections | stickers.CreateStickerSet | stickers.RemoveStickerFromSet | stickers.ChangeStickerPosition | stickers.AddStickerToSet | stickers.SetStickerSetThumb | stickers.CheckShortName | stickers.SuggestShortName | stickers.ChangeSticker | stickers.RenameStickerSet | stickers.DeleteStickerSet | stickers.ReplaceSticker @@ -28328,7 +28485,7 @@ namespace Api { | folders.EditPeerFolders | stats.GetBroadcastStats | stats.LoadAsyncGraph | stats.GetMegagroupStats | stats.GetMessagePublicForwards | stats.GetMessageStats | stats.GetStoryStats | stats.GetStoryPublicForwards | chatlists.ExportChatlistInvite | chatlists.DeleteExportedInvite | chatlists.EditExportedInvite | chatlists.GetExportedInvites | chatlists.CheckChatlistInvite | chatlists.JoinChatlistInvite | chatlists.GetChatlistUpdates | chatlists.JoinChatlistUpdates | chatlists.HideChatlistUpdates | chatlists.GetLeaveChatlistSuggestions | chatlists.LeaveChatlist - | stories.CanSendStory | stories.SendStory | stories.EditStory | stories.DeleteStories | stories.TogglePinned | stories.GetAllStories | stories.GetPinnedStories | stories.GetStoriesArchive | stories.GetStoriesByID | stories.ToggleAllStoriesHidden | stories.ReadStories | stories.IncrementStoryViews | stories.GetStoryViewsList | stories.GetStoriesViews | stories.ExportStoryLink | stories.Report | stories.ActivateStealthMode | stories.SendReaction | stories.GetPeerStories | stories.GetAllReadPeerStories | stories.GetPeerMaxIDs | stories.GetChatsToSend | stories.TogglePeerStoriesHidden | stories.GetStoryReactionsList | stories.TogglePinnedToTop | stories.SearchPosts + | stories.CanSendStory | stories.SendStory | stories.EditStory | stories.DeleteStories | stories.TogglePinned | stories.GetAllStories | stories.GetPinnedStories | stories.GetStoriesArchive | stories.GetStoriesByID | stories.ToggleAllStoriesHidden | stories.ReadStories | stories.IncrementStoryViews | stories.GetStoryViewsList | stories.GetStoriesViews | stories.ExportStoryLink | stories.Report | stories.ActivateStealthMode | stories.SendReaction | stories.GetPeerStories | stories.GetAllReadPeerStories | stories.GetPeerMaxIDs | stories.GetChatsToSend | stories.TogglePeerStoriesHidden | stories.GetStoryReactionsList | stories.TogglePinnedToTop | stories.SearchPosts | stories.CreateAlbum | stories.UpdateAlbum | stories.ReorderAlbums | stories.DeleteAlbum | stories.GetAlbums | stories.GetAlbumStories | premium.GetBoostsList | premium.GetMyBoosts | premium.ApplyBoost | premium.GetBoostsStatus | premium.GetUserBoosts | smsjobs.IsEligibleToJoin | smsjobs.Join | smsjobs.Leave | smsjobs.UpdateSettings | smsjobs.GetStatus | smsjobs.GetSmsJob | smsjobs.FinishJob | fragment.GetCollectibleInfo; diff --git a/src/lib/gramjs/tl/apiTl.ts b/src/lib/gramjs/tl/apiTl.ts index 2435619aa..c51b28785 100644 --- a/src/lib/gramjs/tl/apiTl.ts +++ b/src/lib/gramjs/tl/apiTl.ts @@ -160,7 +160,7 @@ messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_am messageActionGiftStars#45d5b021 flags:# currency:string amount:long stars:long crypto_currency:flags.0?string crypto_amount:flags.0?long transaction_id:flags.1?string = MessageAction; messageActionPrizeStars#b00c47a2 flags:# unclaimed:flags.0?true stars:long transaction_id:string boost_peer:Peer giveaway_msg_id:int = MessageAction; messageActionStarGift#4717e8a4 flags:# name_hidden:flags.0?true saved:flags.2?true converted:flags.3?true upgraded:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true gift:StarGift message:flags.1?TextWithEntities convert_stars:flags.4?long upgrade_msg_id:flags.5?int upgrade_stars:flags.8?long from_id:flags.11?Peer peer:flags.12?Peer saved_id:flags.12?long = MessageAction; -messageActionStarGiftUnique#2e3ae60e flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long resale_stars:flags.8?long can_transfer_at:flags.9?int can_resell_at:flags.10?int = MessageAction; +messageActionStarGiftUnique#34f762f3 flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long resale_amount:flags.8?StarsAmount can_transfer_at:flags.9?int can_resell_at:flags.10?int = MessageAction; messageActionPaidMessagesRefunded#ac1f1fcd count:int stars:long = MessageAction; messageActionPaidMessagesPrice#84b88578 flags:# broadcast_messages_allowed:flags.0?true stars:long = MessageAction; messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true video:flags.4?true call_id:long duration:flags.2?int other_participants:flags.3?Vector = MessageAction; @@ -208,7 +208,7 @@ inputReportReasonGeoIrrelevant#dbd4feed = ReportReason; inputReportReasonFake#f5ddd6e7 = ReportReason; inputReportReasonIllegalDrugs#a8eb2be = ReportReason; inputReportReasonPersonalDetails#9ec7863d = ReportReason; -userFull#29de80be flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings stars_rating:flags2.17?StarsRating = UserFull; +userFull#7e63ce1f flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings stars_rating:flags2.17?StarsRating stars_my_pending_rating:flags2.18?StarsRating stars_my_pending_rating_date:flags2.18?int = UserFull; contact#145ade0b user_id:long mutual:Bool = Contact; importedContact#c13e3c50 user_id:long client_id:long = ImportedContact; contactStatus#16d9703b user_id:long status:UserStatus = ContactStatus; @@ -221,7 +221,7 @@ messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats: messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesSlice#3a54685e flags:# inexact:flags.1?true count:int next_rate:flags.0?int offset_id_offset:flags.2?int messages:Vector chats:Vector users:Vector = messages.Messages; +messages.messagesSlice#762b263d flags:# inexact:flags.1?true count:int next_rate:flags.0?int offset_id_offset:flags.2?int search_flood:flags.3?SearchPostsFlood messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#c776ba4e flags:# inexact:flags.1?true pts:int count:int offset_id_offset:flags.2?int messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; messages.messagesNotModified#74535f21 count:int = messages.Messages; messages.chats#64ff9fd5 chats:Vector = messages.Chats; @@ -1020,6 +1020,7 @@ webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector settin webPageAttributeStory#2e94c3e7 flags:# peer:Peer id:int story:flags.0?StoryItem = WebPageAttribute; webPageAttributeStickerSet#50cc03d3 flags:# emojis:flags.0?true text_color:flags.1?true stickers:Vector = WebPageAttribute; webPageAttributeUniqueStarGift#cf6f6db8 gift:StarGift = WebPageAttribute; +webPageAttributeStarGiftCollection#31cad303 icons:Vector = WebPageAttribute; messages.votesList#4899484e flags:# count:int votes:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.VotesList; bankCardOpenUrl#f568028a url:string name:string = BankCardOpenUrl; payments.bankCardData#3e24e573 title:string open_urls:Vector = payments.BankCardData; @@ -1151,7 +1152,7 @@ inputInvoiceStarGiftUpgrade#4d818d5d flags:# keep_original_details:flags.0?true inputInvoiceStarGiftTransfer#4a5f5bd9 stargift:InputSavedStarGift to_id:InputPeer = InputInvoice; inputInvoicePremiumGiftStars#dabab2ef flags:# user_id:InputUser months:int message:flags.0?TextWithEntities = InputInvoice; inputInvoiceBusinessBotTransferStars#f4997e42 bot:InputUser stars:long = InputInvoice; -inputInvoiceStarGiftResale#63cbc38c slug:string to_id:InputPeer = InputInvoice; +inputInvoiceStarGiftResale#c39f5324 flags:# ton:flags.0?true slug:string to_id:InputPeer = InputInvoice; payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice; messages.transcribedAudio#cfb9d957 flags:# pending:flags.0?true transcription_id:long text:string trial_remains_num:flags.1?int trial_remains_until_date:flags.1?int = messages.TranscribedAudio; help.premiumPromo#5334759c status_text:string status_entities:Vector video_sections:Vector videos:Vector period_options:Vector users:Vector = help.PremiumPromo; @@ -1236,7 +1237,7 @@ messagePeerVoteMultiple#4628f6e6 peer:Peer options:Vector date:int = Mess storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_count:flags.2?int reactions:flags.3?Vector reactions_count:flags.4?int recent_viewers:flags.0?Vector = StoryViews; storyItemDeleted#51e6ee4f id:int = StoryItem; storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true id:int date:int expire_date:int = StoryItem; -storyItem#79b26a24 flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int from_id:flags.18?Peer fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector media:MessageMedia media_areas:flags.14?Vector privacy:flags.2?Vector views:flags.3?StoryViews sent_reaction:flags.15?Reaction = StoryItem; +storyItem#edf164f1 flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int from_id:flags.18?Peer fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector media:MessageMedia media_areas:flags.14?Vector privacy:flags.2?Vector views:flags.3?StoryViews sent_reaction:flags.15?Reaction albums:flags.19?Vector = StoryItem; stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories; stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector chats:Vector users:Vector stealth_mode:StoriesStealthMode = stories.AllStories; stories.stories#63c3dd0a flags:# count:int stories:Vector pinned_to_top:flags.0?Vector chats:Vector users:Vector = stories.Stories; @@ -1387,7 +1388,7 @@ messageReactor#4ba3a95a flags:# top:flags.0?true my:flags.1?true anonymous:flags starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true stars:long yearly_boosts:int store_product:flags.2?string currency:string amount:long winners:Vector = StarsGiveawayOption; starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption; starGift#bcff5b flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true require_premium:flags.7?true limited_per_user:flags.8?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string released_by:flags.6?Peer per_user_total:flags.8?int per_user_remains:flags.8?int = StarGift; -starGiftUnique#f63778ae flags:# require_premium:flags.6?true id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector availability_issued:int availability_total:int gift_address:flags.3?string resell_stars:flags.4?long released_by:flags.5?Peer = StarGift; +starGiftUnique#3a274d50 flags:# require_premium:flags.6?true resale_ton_only:flags.7?true id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector availability_issued:int availability_total:int gift_address:flags.3?string resell_amount:flags.4?Vector released_by:flags.5?Peer = StarGift; payments.starGiftsNotModified#a388a368 = payments.StarGifts; payments.starGifts#2ed82995 hash:int gifts:Vector chats:Vector users:Vector = payments.StarGifts; messageReportOption#7903e3d9 text:string option:bytes = MessageReportOption; @@ -1449,6 +1450,10 @@ starsRating#1b0e4f07 flags:# level:int current_level_stars:long stars:long next_ starGiftCollection#9d6b13b0 flags:# collection_id:int title:string icon:flags.0?Document gifts_count:int hash:long = StarGiftCollection; payments.starGiftCollectionsNotModified#a0ba4f17 = payments.StarGiftCollections; payments.starGiftCollections#8a2932f3 collections:Vector = payments.StarGiftCollections; +storyAlbum#9325705a flags:# album_id:int title:string icon_photo:flags.0?Photo icon_video:flags.1?Document = StoryAlbum; +stories.albumsNotModified#564edaeb = stories.Albums; +stories.albums#c3987a3a hash:long albums:Vector = stories.Albums; +searchPostsFlood#3e0b5b6a flags:# query_is_free:flags.0?true total_daily:int remains:int wait_till:flags.1?int stars_amount:long = SearchPostsFlood; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X; @@ -1743,7 +1748,7 @@ channels.deleteTopicHistory#34435f2d channel:InputChannel top_msg_id:int = messa channels.toggleParticipantsHidden#6a6e7854 channel:InputChannel enabled:Bool = Updates; channels.toggleViewForumAsMessages#9738bb15 channel:InputChannel enabled:Bool = Updates; channels.getChannelRecommendations#25a71742 flags:# channel:flags.0?InputChannel = messages.Chats; -channels.searchPosts#d19f987b hashtag:string offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; +channels.searchPosts#f2c4f24d flags:# hashtag:flags.0?string query:flags.1?string offset_rate:int offset_peer:InputPeer offset_id:int limit:int allow_paid_stars:flags.2?long = messages.Messages; channels.updatePaidMessagesPrice#4b12327b flags:# broadcast_messages_allowed:flags.0?true channel:InputChannel send_paid_messages_stars:long = Updates; channels.toggleAutotranslation#167fc0a1 channel:InputChannel enabled:Bool = Updates; bots.setBotInfo#10cf3123 flags:# bot:flags.2?InputUser lang_code:string name:flags.3?string about:flags.0?string description:flags.1?string = Bool; @@ -1787,7 +1792,7 @@ payments.getSavedStarGifts#a319e569 flags:# exclude_unsaved:flags.0?true exclude payments.getStarGiftWithdrawalUrl#d06e93a8 stargift:InputSavedStarGift password:InputCheckPasswordSRP = payments.StarGiftWithdrawalUrl; payments.toggleStarGiftsPinnedToTop#1513e7b0 peer:InputPeer stargift:Vector = Bool; payments.getResaleStarGifts#7a5fa236 flags:# sort_by_price:flags.1?true sort_by_num:flags.2?true attributes_hash:flags.0?long gift_id:long attributes:flags.3?Vector offset:string limit:int = payments.ResaleStarGifts; -payments.updateStarGiftPrice#3baea4e1 stargift:InputSavedStarGift resell_stars:long = Updates; +payments.updateStarGiftPrice#edbe6ccb stargift:InputSavedStarGift resell_amount:StarsAmount = Updates; phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; diff --git a/src/lib/gramjs/tl/static/api.tl b/src/lib/gramjs/tl/static/api.tl index 4bf0503b7..051f1ba62 100644 --- a/src/lib/gramjs/tl/static/api.tl +++ b/src/lib/gramjs/tl/static/api.tl @@ -186,7 +186,7 @@ messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_am messageActionGiftStars#45d5b021 flags:# currency:string amount:long stars:long crypto_currency:flags.0?string crypto_amount:flags.0?long transaction_id:flags.1?string = MessageAction; messageActionPrizeStars#b00c47a2 flags:# unclaimed:flags.0?true stars:long transaction_id:string boost_peer:Peer giveaway_msg_id:int = MessageAction; messageActionStarGift#4717e8a4 flags:# name_hidden:flags.0?true saved:flags.2?true converted:flags.3?true upgraded:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true gift:StarGift message:flags.1?TextWithEntities convert_stars:flags.4?long upgrade_msg_id:flags.5?int upgrade_stars:flags.8?long from_id:flags.11?Peer peer:flags.12?Peer saved_id:flags.12?long = MessageAction; -messageActionStarGiftUnique#2e3ae60e flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long resale_stars:flags.8?long can_transfer_at:flags.9?int can_resell_at:flags.10?int = MessageAction; +messageActionStarGiftUnique#34f762f3 flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long resale_amount:flags.8?StarsAmount can_transfer_at:flags.9?int can_resell_at:flags.10?int = MessageAction; messageActionPaidMessagesRefunded#ac1f1fcd count:int stars:long = MessageAction; messageActionPaidMessagesPrice#84b88578 flags:# broadcast_messages_allowed:flags.0?true stars:long = MessageAction; messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true video:flags.4?true call_id:long duration:flags.2?int other_participants:flags.3?Vector = MessageAction; @@ -248,7 +248,7 @@ inputReportReasonFake#f5ddd6e7 = ReportReason; inputReportReasonIllegalDrugs#a8eb2be = ReportReason; inputReportReasonPersonalDetails#9ec7863d = ReportReason; -userFull#29de80be flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings stars_rating:flags2.17?StarsRating = UserFull; +userFull#7e63ce1f flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings stars_rating:flags2.17?StarsRating stars_my_pending_rating:flags2.18?StarsRating stars_my_pending_rating_date:flags2.18?int = UserFull; contact#145ade0b user_id:long mutual:Bool = Contact; @@ -269,7 +269,7 @@ messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector< messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesSlice#3a54685e flags:# inexact:flags.1?true count:int next_rate:flags.0?int offset_id_offset:flags.2?int messages:Vector chats:Vector users:Vector = messages.Messages; +messages.messagesSlice#762b263d flags:# inexact:flags.1?true count:int next_rate:flags.0?int offset_id_offset:flags.2?int search_flood:flags.3?SearchPostsFlood messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#c776ba4e flags:# inexact:flags.1?true pts:int count:int offset_id_offset:flags.2?int messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; messages.messagesNotModified#74535f21 count:int = messages.Messages; @@ -1289,6 +1289,7 @@ webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector settin webPageAttributeStory#2e94c3e7 flags:# peer:Peer id:int story:flags.0?StoryItem = WebPageAttribute; webPageAttributeStickerSet#50cc03d3 flags:# emojis:flags.0?true text_color:flags.1?true stickers:Vector = WebPageAttribute; webPageAttributeUniqueStarGift#cf6f6db8 gift:StarGift = WebPageAttribute; +webPageAttributeStarGiftCollection#31cad303 icons:Vector = WebPageAttribute; messages.votesList#4899484e flags:# count:int votes:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.VotesList; @@ -1502,7 +1503,7 @@ inputInvoiceStarGiftUpgrade#4d818d5d flags:# keep_original_details:flags.0?true inputInvoiceStarGiftTransfer#4a5f5bd9 stargift:InputSavedStarGift to_id:InputPeer = InputInvoice; inputInvoicePremiumGiftStars#dabab2ef flags:# user_id:InputUser months:int message:flags.0?TextWithEntities = InputInvoice; inputInvoiceBusinessBotTransferStars#f4997e42 bot:InputUser stars:long = InputInvoice; -inputInvoiceStarGiftResale#63cbc38c slug:string to_id:InputPeer = InputInvoice; +inputInvoiceStarGiftResale#c39f5324 flags:# ton:flags.0?true slug:string to_id:InputPeer = InputInvoice; payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice; @@ -1634,7 +1635,7 @@ storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_co storyItemDeleted#51e6ee4f id:int = StoryItem; storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true id:int date:int expire_date:int = StoryItem; -storyItem#79b26a24 flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int from_id:flags.18?Peer fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector media:MessageMedia media_areas:flags.14?Vector privacy:flags.2?Vector views:flags.3?StoryViews sent_reaction:flags.15?Reaction = StoryItem; +storyItem#edf164f1 flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int from_id:flags.18?Peer fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector media:MessageMedia media_areas:flags.14?Vector privacy:flags.2?Vector views:flags.3?StoryViews sent_reaction:flags.15?Reaction albums:flags.19?Vector = StoryItem; stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories; stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector chats:Vector users:Vector stealth_mode:StoriesStealthMode = stories.AllStories; @@ -1891,7 +1892,7 @@ starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption; starGift#bcff5b flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true require_premium:flags.7?true limited_per_user:flags.8?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string released_by:flags.6?Peer per_user_total:flags.8?int per_user_remains:flags.8?int = StarGift; -starGiftUnique#f63778ae flags:# require_premium:flags.6?true id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector availability_issued:int availability_total:int gift_address:flags.3?string resell_stars:flags.4?long released_by:flags.5?Peer = StarGift; +starGiftUnique#3a274d50 flags:# require_premium:flags.6?true resale_ton_only:flags.7?true id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector availability_issued:int availability_total:int gift_address:flags.3?string resell_amount:flags.4?Vector released_by:flags.5?Peer = StarGift; payments.starGiftsNotModified#a388a368 = payments.StarGifts; payments.starGifts#2ed82995 hash:int gifts:Vector chats:Vector users:Vector = payments.StarGifts; @@ -1996,6 +1997,13 @@ starGiftCollection#9d6b13b0 flags:# collection_id:int title:string icon:flags.0? payments.starGiftCollectionsNotModified#a0ba4f17 = payments.StarGiftCollections; payments.starGiftCollections#8a2932f3 collections:Vector = payments.StarGiftCollections; +storyAlbum#9325705a flags:# album_id:int title:string icon_photo:flags.0?Photo icon_video:flags.1?Document = StoryAlbum; + +stories.albumsNotModified#564edaeb = stories.Albums; +stories.albums#c3987a3a hash:long albums:Vector = stories.Albums; + +searchPostsFlood#3e0b5b6a flags:# query_is_free:flags.0?true total_daily:int remains:int wait_till:flags.1?int stars_amount:long = SearchPostsFlood; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -2519,10 +2527,11 @@ channels.updateEmojiStatus#f0d3e6a8 channel:InputChannel emoji_status:EmojiStatu channels.setBoostsToUnblockRestrictions#ad399cee channel:InputChannel boosts:int = Updates; channels.setEmojiStickers#3cd930b7 channel:InputChannel stickerset:InputStickerSet = Bool; channels.restrictSponsoredMessages#9ae91519 channel:InputChannel restricted:Bool = Updates; -channels.searchPosts#d19f987b hashtag:string offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; +channels.searchPosts#f2c4f24d flags:# hashtag:flags.0?string query:flags.1?string offset_rate:int offset_peer:InputPeer offset_id:int limit:int allow_paid_stars:flags.2?long = messages.Messages; channels.updatePaidMessagesPrice#4b12327b flags:# broadcast_messages_allowed:flags.0?true channel:InputChannel send_paid_messages_stars:long = Updates; channels.toggleAutotranslation#167fc0a1 channel:InputChannel enabled:Bool = Updates; channels.getMessageAuthor#ece2a0e6 channel:InputChannel id:int = User; +channels.checkSearchPostsFlood#22567115 flags:# query:flags.0?string = SearchPostsFlood; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; @@ -2604,7 +2613,7 @@ payments.toggleChatStarGiftNotifications#60eaefa1 flags:# enabled:flags.0?true p payments.toggleStarGiftsPinnedToTop#1513e7b0 peer:InputPeer stargift:Vector = Bool; payments.canPurchaseStore#4fdc5ea7 purpose:InputStorePaymentPurpose = Bool; payments.getResaleStarGifts#7a5fa236 flags:# sort_by_price:flags.1?true sort_by_num:flags.2?true attributes_hash:flags.0?long gift_id:long attributes:flags.3?Vector offset:string limit:int = payments.ResaleStarGifts; -payments.updateStarGiftPrice#3baea4e1 stargift:InputSavedStarGift resell_stars:long = Updates; +payments.updateStarGiftPrice#edbe6ccb stargift:InputSavedStarGift resell_amount:StarsAmount = Updates; payments.createStarGiftCollection#1f4a0e87 peer:InputPeer title:string stargift:Vector = StarGiftCollection; payments.updateStarGiftCollection#4fddbee7 flags:# peer:InputPeer collection_id:int title:flags.0?string delete_stargift:flags.1?Vector add_stargift:flags.2?Vector order:flags.3?Vector = StarGiftCollection; payments.reorderStarGiftCollections#c32af4cc peer:InputPeer order:Vector = Bool; @@ -2690,7 +2699,7 @@ chatlists.getLeaveChatlistSuggestions#fdbcd714 chatlist:InputChatlist = Vector

= Updates; stories.canSendStory#30eb63f0 peer:InputPeer = stories.CanSendStoryCount; -stories.sendStory#e4e6694b flags:# pinned:flags.2?true noforwards:flags.4?true fwd_modified:flags.7?true peer:InputPeer media:InputMedia media_areas:flags.5?Vector caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long period:flags.3?int fwd_from_id:flags.6?InputPeer fwd_from_story:flags.6?int = Updates; +stories.sendStory#737fc2ec flags:# pinned:flags.2?true noforwards:flags.4?true fwd_modified:flags.7?true peer:InputPeer media:InputMedia media_areas:flags.5?Vector caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long period:flags.3?int fwd_from_id:flags.6?InputPeer fwd_from_story:flags.6?int albums:flags.8?Vector = Updates; stories.editStory#b583ba46 flags:# peer:InputPeer id:int media:flags.0?InputMedia media_areas:flags.3?Vector caption:flags.1?string entities:flags.1?Vector privacy_rules:flags.2?Vector = Updates; stories.deleteStories#ae59db5f peer:InputPeer id:Vector = Vector; stories.togglePinned#9a75a1ef peer:InputPeer id:Vector pinned:Bool = Vector; @@ -2715,6 +2724,12 @@ stories.togglePeerStoriesHidden#bd0415c4 peer:InputPeer hidden:Bool = Bool; stories.getStoryReactionsList#b9b2881f flags:# forwards_first:flags.2?true peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = stories.StoryReactionsList; stories.togglePinnedToTop#b297e9b peer:InputPeer id:Vector = Bool; stories.searchPosts#d1810907 flags:# hashtag:flags.0?string area:flags.1?MediaArea peer:flags.2?InputPeer offset:string limit:int = stories.FoundStories; +stories.createAlbum#a36396e5 peer:InputPeer title:string stories:Vector = StoryAlbum; +stories.updateAlbum#5e5259b6 flags:# peer:InputPeer album_id:int title:flags.0?string delete_stories:flags.1?Vector add_stories:flags.2?Vector order:flags.3?Vector = StoryAlbum; +stories.reorderAlbums#8535fbd9 peer:InputPeer order:Vector = Bool; +stories.deleteAlbum#8d3456d0 peer:InputPeer album_id:int = Bool; +stories.getAlbums#25b3eac7 peer:InputPeer hash:long = stories.Albums; +stories.getAlbumStories#ac806d61 peer:InputPeer album_id:int offset:int limit:int = stories.Stories; premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList; premium.getMyBoosts#be77b4a = premium.MyBoosts; diff --git a/src/types/language.d.ts b/src/types/language.d.ts index e96de38ae..22702f270 100644 --- a/src/types/language.d.ts +++ b/src/types/language.d.ts @@ -1608,6 +1608,14 @@ export interface LangPair { 'TitleAgeCheckFailed': undefined; 'TitleAgeCheckSuccess': undefined; 'ButtonAgeVerification': undefined; + 'PriceInStars': undefined; + 'PriceInTON': undefined; + 'OnlyAcceptTON': undefined; + 'OnlyAcceptTONDescription': undefined; + 'DescriptionPayInTON': undefined; + 'LabelPayInTON': undefined; + 'PriceChanged': undefined; + 'PayNewPrice': undefined; } export interface LangPairWithVariables { @@ -2785,6 +2793,19 @@ export interface LangPairWithVariables { 'ButtonSensitiveAlways': { 'years': V; }; + 'DescriptionComposerGiftMinimumCurrencyPrice': { + 'amount': V; + }; + 'DescriptionComposerGiftResaleCurrencyPrice': { + 'amount': V; + }; + 'ButtonSellGiftTon': { + 'amount': V; + }; + 'PriceChangedText': { + 'originalAmount': V; + 'newAmount': V; + }; } export interface LangPairPlural { diff --git a/src/util/formatCurrency.tsx b/src/util/formatCurrency.tsx index ab2f249f9..c1d5c501a 100644 --- a/src/util/formatCurrency.tsx +++ b/src/util/formatCurrency.tsx @@ -38,14 +38,14 @@ export function formatCurrency( } if (currency === TON_CURRENCY_CODE) { - return formatTonAsIcon(lang, price, { asFont: options?.asFontIcon, className: options?.iconClassName }); + return formatTonAsIcon(lang, price, { className: options?.iconClassName }); } return formatCurrencyAsString(totalPrice, currency, lang.code, options); } -export function convertTonToUsd(amount: number, usdRate: number): number { - const tonInRegularUnits = convertTonFromNanos(amount); +export function convertTonToUsd(amount: number, usdRate: number, isInNanos: boolean = false): number { + const tonInRegularUnits = isInNanos ? convertTonFromNanos(amount) : amount; return tonInRegularUnits * usdRate * 100; } diff --git a/src/util/localization/format.tsx b/src/util/localization/format.tsx index b882363d9..c38af1b7c 100644 --- a/src/util/localization/format.tsx +++ b/src/util/localization/format.tsx @@ -1,7 +1,7 @@ import type { LangFn } from './types'; import { STARS_ICON_PLACEHOLDER } from '../../config'; -import { convertCurrencyFromBaseUnit } from '../../util/formatCurrency'; +import { convertTonFromNanos } from '../../util/formatCurrency'; import buildClassName from '../buildClassName'; import Icon from '../../components/common/icons/Icon'; @@ -11,14 +11,19 @@ export function formatStarsAsText(lang: LangFn, amount: number) { return lang('StarsAmountText', { amount }, { pluralValue: amount }); } -export function formatTonAsText(lang: LangFn, amount: number) { - return lang('TonAmountText', { amount: lang.preciseNumber(amount) }, { pluralValue: amount }); +export function formatTonAsText(lang: LangFn, amount: number, shouldConvertFromNanos?: boolean) { + const formattedAmount = shouldConvertFromNanos ? convertTonFromNanos(Number(amount)) : amount; + return lang('TonAmountText', { amount: lang.preciseNumber(formattedAmount) }, { pluralValue: formattedAmount }); } -export function formatTonAsIcon(lang: LangFn, amount: number | string, options?: { - asFont?: boolean; className?: string; containerClassName?: string; shouldConvertFromNanos?: boolean; }) { +export function formatTonAsIcon( + lang: LangFn, + amount: number | string, + options?: { + className?: string; containerClassName?: string; shouldConvertFromNanos?: boolean; + }) { const { className, containerClassName, shouldConvertFromNanos } = options || {}; - const formattedAmount = shouldConvertFromNanos ? convertCurrencyFromBaseUnit(Number(amount), 'TON') : amount; + const formattedAmount = shouldConvertFromNanos ? convertTonFromNanos(Number(amount)) : amount; const icon = ; if (containerClassName) {