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