From 10009ce9baf41a753b9baf5f9226f5b0fe3b4d4b Mon Sep 17 00:00:00 2001 From: zubiden <19638254+zubiden@users.noreply.github.com> Date: Mon, 27 Jan 2025 23:50:53 +0100 Subject: [PATCH] Gifts: Support channels (#5527) --- src/api/gramjs/apiBuilders/gifts.ts | 25 +- src/api/gramjs/apiBuilders/messages.ts | 47 ++- src/api/gramjs/apiBuilders/peers.ts | 5 +- src/api/gramjs/gramjsBuilders/index.ts | 28 +- src/api/gramjs/methods/chats.ts | 4 + src/api/gramjs/methods/payments.ts | 41 ++- src/api/types/chats.ts | 2 + src/api/types/messages.ts | 157 +-------- src/api/types/payments.ts | 171 +++++++++- src/api/types/users.ts | 6 +- src/assets/localization/fallback.strings | 41 ++- ...Gift.module.scss => SavedGift.module.scss} | 0 .../gift/{UserGift.tsx => SavedGift.tsx} | 24 +- src/components/middle/ActionMessage.tsx | 48 ++- src/components/modals/gift/GiftComposer.tsx | 60 ++-- src/components/modals/gift/GiftModal.tsx | 53 +-- .../modals/gift/StarGiftCategoryList.tsx | 2 +- .../gift/info/GiftInfoModal.module.scss | 15 + .../modals/gift/info/GiftInfoModal.tsx | 196 +++++++---- .../modals/gift/upgrade/GiftUpgradeModal.tsx | 7 +- .../modals/stars/StarsBalanceModal.tsx | 10 +- src/components/right/Profile.tsx | 20 +- src/global/actions/api/payments.ts | 18 +- src/global/actions/api/stars.ts | 58 ++-- src/global/actions/apiUpdaters/misc.ts | 7 +- src/global/actions/apiUpdaters/payments.ts | 2 +- src/global/actions/ui/stars.ts | 11 +- src/global/cache.ts | 17 +- src/global/helpers/messages.ts | 12 +- src/global/helpers/payments.ts | 43 ++- src/global/initialState.ts | 7 +- src/global/reducers/peers.ts | 14 +- src/global/reducers/users.ts | 16 +- src/global/selectors/peers.ts | 18 +- src/global/selectors/users.ts | 9 - src/global/types/actions.ts | 19 +- src/global/types/globalState.ts | 9 +- src/global/types/tabState.ts | 12 +- src/lib/gramjs/tl/AllTLObjects.ts | 2 +- src/lib/gramjs/tl/api.d.ts | 322 ++++++++++++------ src/lib/gramjs/tl/apiTl.ts | 51 +-- src/lib/gramjs/tl/static/api.json | 2 +- src/lib/gramjs/tl/static/api.tl | 62 ++-- src/types/index.ts | 2 +- src/types/language.d.ts | 63 ++-- 45 files changed, 1075 insertions(+), 663 deletions(-) rename src/components/common/gift/{UserGift.module.scss => SavedGift.module.scss} (100%) rename src/components/common/gift/{UserGift.tsx => SavedGift.tsx} (86%) diff --git a/src/api/gramjs/apiBuilders/gifts.ts b/src/api/gramjs/apiBuilders/gifts.ts index e0307d4e2..d5fa6d2d0 100644 --- a/src/api/gramjs/apiBuilders/gifts.ts +++ b/src/api/gramjs/apiBuilders/gifts.ts @@ -1,29 +1,31 @@ import { Api as GramJs } from '../../../lib/gramjs'; import type { + ApiInputSavedStarGift, + ApiSavedStarGift, ApiStarGift, ApiStarGiftAttribute, - ApiUserStarGift, } from '../../types'; import { numberToHexColor } from '../../../util/colors'; import { addDocumentToLocalDb } from '../helpers'; import { buildApiFormattedText } from './common'; -import { buildApiPeerId } from './peers'; +import { getApiChatIdFromMtpPeer } from './peers'; import { buildStickerFromDocument } from './symbols'; export function buildApiStarGift(starGift: GramJs.TypeStarGift): ApiStarGift { if (starGift instanceof GramJs.StarGiftUnique) { const { - id, num, ownerId, ownerName, title, attributes, availabilityIssued, availabilityTotal, slug, + id, num, ownerId, ownerName, title, attributes, availabilityIssued, availabilityTotal, slug, ownerAddress, } = starGift; return { type: 'starGiftUnique', id: id.toString(), number: num, - ownerId: ownerId && buildApiPeerId(ownerId, 'user'), + ownerId: ownerId && getApiChatIdFromMtpPeer(ownerId), ownerName, + ownerAddress, attributes: attributes.map(buildApiStarGiftAttribute).filter(Boolean), title, totalCount: availabilityTotal, @@ -115,25 +117,30 @@ export function buildApiStarGiftAttribute(attribute: GramJs.TypeStarGiftAttribut return { type: 'originalDetails', date, - recipientId: recipientId && buildApiPeerId(recipientId, 'user'), + recipientId: recipientId && getApiChatIdFromMtpPeer(recipientId), message: message && buildApiFormattedText(message), - senderId: senderId && buildApiPeerId(senderId, 'user'), + senderId: senderId && getApiChatIdFromMtpPeer(senderId), }; } return undefined; } -export function buildApiUserStarGift(userStarGift: GramJs.UserStarGift): ApiUserStarGift { +export function buildApiSavedStarGift(userStarGift: GramJs.SavedStarGift, peerId: string): ApiSavedStarGift { const { gift, date, convertStars, fromId, message, msgId, nameHidden, unsaved, upgradeStars, transferStars, canUpgrade, + savedId, } = userStarGift; + const inputGift: ApiInputSavedStarGift | undefined = savedId && peerId + ? { type: 'chat', chatId: peerId, savedId: savedId.toString() } + : msgId ? { type: 'user', messageId: msgId } : undefined; + return { gift: buildApiStarGift(gift), date, starsToConvert: convertStars?.toJSNumber(), - fromId: fromId && buildApiPeerId(fromId, 'user'), + fromId: fromId && getApiChatIdFromMtpPeer(fromId), message: message && buildApiFormattedText(message), messageId: msgId, isNameHidden: nameHidden, @@ -141,5 +148,7 @@ export function buildApiUserStarGift(userStarGift: GramJs.UserStarGift): ApiUser canUpgrade, alreadyPaidUpgradeStars: upgradeStars?.toJSNumber(), transferStars: transferStars?.toJSNumber(), + inputGift, + savedId: savedId?.toString(), }; } diff --git a/src/api/gramjs/apiBuilders/messages.ts b/src/api/gramjs/apiBuilders/messages.ts index 10c0f8d97..4c4d7c838 100644 --- a/src/api/gramjs/apiBuilders/messages.ts +++ b/src/api/gramjs/apiBuilders/messages.ts @@ -11,6 +11,7 @@ import type { ApiGroupCall, ApiInputMessageReplyInfo, ApiInputReplyInfo, + ApiInputSavedStarGift, ApiKeyboardButton, ApiMessage, ApiMessageActionStarGift, @@ -193,7 +194,7 @@ export function buildApiMessageWithChatId( : isSavedOutgoing; const content = buildMessageContent(mtpMessage); const action = mtpMessage.action - && buildAction(mtpMessage.action, fromId, peerId, Boolean(mtpMessage.post), isOutgoing); + && buildAction(mtpMessage.action, mtpMessage.id, fromId, peerId, Boolean(mtpMessage.post), isOutgoing); if (action) { content.action = action; } @@ -369,16 +370,29 @@ export function buildApiFactCheck(factCheck: GramJs.FactCheck): ApiFactCheck { }; } -function buildApiMessageActionStarGift(action: GramJs.MessageActionStarGift) : ApiMessageActionStarGift { +function buildApiMessageActionStarGift( + action: GramJs.MessageActionStarGift, messageId: number, +): ApiMessageActionStarGift { const { nameHidden, saved, converted, gift, message, convertStars, canUpgrade, upgraded, upgradeMsgId, upgradeStars, + peer, savedId, fromId, } = action; + const inputSavedGift: ApiInputSavedStarGift = savedId && peer ? { + type: 'chat', + chatId: getApiChatIdFromMtpPeer(peer), + savedId: savedId.toString(), + } : { + type: 'user', + messageId, + }; + return { type: 'starGift', isNameHidden: Boolean(nameHidden), isSaved: Boolean(saved), isConverted: converted, + fromId: fromId && getApiChatIdFromMtpPeer(fromId), gift: buildApiStarGift(gift) as ApiStarGiftRegular, message: message && buildApiFormattedText(message), starsToConvert: convertStars?.toJSNumber(), @@ -386,16 +400,28 @@ function buildApiMessageActionStarGift(action: GramJs.MessageActionStarGift) : A isUpgraded: upgraded, upgradeMsgId, alreadyPaidUpgradeStars: upgradeStars?.toJSNumber(), + peerId: peer && getApiChatIdFromMtpPeer(peer), + savedId: savedId?.toString(), + inputSavedGift, }; } function buildApiMessageActionStarGiftUnique( - action: GramJs.MessageActionStarGiftUnique, + action: GramJs.MessageActionStarGiftUnique, messageId: number, ): ApiMessageActionStarGiftUnique { const { - gift, canExportAt, refunded, saved, transferStars, transferred, upgrade, + gift, canExportAt, refunded, saved, transferStars, transferred, upgrade, fromId, peer, savedId, } = action; + const inputSavedGift: ApiInputSavedStarGift = savedId && peer ? { + type: 'chat', + chatId: getApiChatIdFromMtpPeer(peer), + savedId: savedId.toString(), + } : { + type: 'user', + messageId, + }; + return { type: 'starGiftUnique', gift: buildApiStarGift(gift) as ApiStarGiftUnique, @@ -405,11 +431,16 @@ function buildApiMessageActionStarGiftUnique( transferStars: transferStars?.toJSNumber(), isTransferred: transferred, isUpgrade: upgrade, + fromId: fromId && getApiChatIdFromMtpPeer(fromId), + peerId: peer && getApiChatIdFromMtpPeer(peer), + savedId: savedId?.toString(), + inputSavedGift, }; } function buildAction( action: GramJs.TypeMessageAction, + messageId: number, senderId: string | undefined, targetPeerId: string | undefined, isChannelPost: boolean, @@ -738,7 +769,7 @@ function buildAction( transactionId = action.transactionId; } else if (action instanceof GramJs.MessageActionStarGift && action.gift instanceof GramJs.StarGift) { type = 'starGift'; - starGift = buildApiMessageActionStarGift(action); + starGift = buildApiMessageActionStarGift(action, messageId); if (isOutgoing) { text = 'ActionGiftOutbound'; translationValues.push('%gift_payment_amount%'); @@ -763,9 +794,11 @@ function buildAction( translationValues.push('%action_origin_chat%'); } - starGift = buildApiMessageActionStarGiftUnique(action); + starGift = buildApiMessageActionStarGiftUnique(action, messageId); - if (targetPeerId) { + if (action.peer) { + targetChatId = getApiChatIdFromMtpPeer(action.peer); + } else if (targetPeerId) { targetUserIds.push(targetPeerId); targetChatId = targetPeerId; } diff --git a/src/api/gramjs/apiBuilders/peers.ts b/src/api/gramjs/apiBuilders/peers.ts index a0b25404b..6dc3da250 100644 --- a/src/api/gramjs/apiBuilders/peers.ts +++ b/src/api/gramjs/apiBuilders/peers.ts @@ -52,10 +52,11 @@ export function buildApiPeerColor(peerColor: GramJs.TypePeerColor): ApiPeerColor export function buildApiEmojiStatus(mtpEmojiStatus: GramJs.TypeEmojiStatus): ApiEmojiStatus | undefined { if (mtpEmojiStatus instanceof GramJs.EmojiStatus) { - return { documentId: mtpEmojiStatus.documentId.toString() }; + return { documentId: mtpEmojiStatus.documentId.toString(), until: mtpEmojiStatus.until }; } - if (mtpEmojiStatus instanceof GramJs.EmojiStatusUntil) { + // TODO: Support other parameters + if (mtpEmojiStatus instanceof GramJs.EmojiStatusCollectible) { return { documentId: mtpEmojiStatus.documentId.toString(), until: mtpEmojiStatus.until }; } diff --git a/src/api/gramjs/gramjsBuilders/index.ts b/src/api/gramjs/gramjsBuilders/index.ts index c5ad1f416..241cc026b 100644 --- a/src/api/gramjs/gramjsBuilders/index.ts +++ b/src/api/gramjs/gramjsBuilders/index.ts @@ -23,6 +23,7 @@ import type { ApiReactionWithPaid, ApiReportReason, ApiRequestInputInvoice, + ApiRequestInputSavedStarGift, ApiSendMessageAction, ApiSticker, ApiStory, @@ -643,10 +644,10 @@ export function buildInputInvoice(invoice: ApiRequestInputInvoice) { case 'stargift': { const { - user, shouldHideName, giftId, message, shouldUpgrade, + peer, shouldHideName, giftId, message, shouldUpgrade, } = invoice; return new GramJs.InputInvoiceStarGift({ - userId: buildInputEntity(user.id, user.accessHash) as GramJs.InputUser, + peer: buildInputPeer(peer.id, peer.accessHash), hideName: shouldHideName || undefined, giftId: BigInt(giftId), message: message && buildInputTextWithEntities(message), @@ -676,7 +677,7 @@ export function buildInputInvoice(invoice: ApiRequestInputInvoice) { case 'stargiftUpgrade': { return new GramJs.InputInvoiceStarGiftUpgrade({ - msgId: invoice.messageId, + stargift: buildInputSavedStarGift(invoice.inputSavedGift), keepOriginalDetails: invoice.shouldKeepOriginalDetails, }); } @@ -732,15 +733,9 @@ export function buildInputEmojiStatus(emojiStatusId: string, expires?: number) { return new GramJs.EmojiStatusEmpty(); } - if (expires) { - return new GramJs.EmojiStatusUntil({ - documentId: BigInt(emojiStatusId), - until: expires, - }); - } - return new GramJs.EmojiStatus({ documentId: BigInt(emojiStatusId), + until: expires, }); } @@ -845,3 +840,16 @@ export function buildInputPrivacyRules( return privacyRules; } + +export function buildInputSavedStarGift(inputGift: ApiRequestInputSavedStarGift) { + if (inputGift.type === 'user') { + return new GramJs.InputSavedStarGiftUser({ + msgId: inputGift.messageId, + }); + } + + return new GramJs.InputSavedStarGiftChat({ + peer: buildInputPeer(inputGift.chat.id, inputGift.chat.accessHash), + savedId: BigInt(inputGift.savedId), + }); +} diff --git a/src/api/gramjs/methods/chats.ts b/src/api/gramjs/methods/chats.ts index 6101ad0d3..5acc8c53f 100644 --- a/src/api/gramjs/methods/chats.ts +++ b/src/api/gramjs/methods/chats.ts @@ -608,6 +608,8 @@ async function getFullChannelInfo( canViewRevenue: canViewMonetization, paidReactionsAvailable, hasScheduled, + stargiftsCount, + stargiftsAvailable, } = result.fullChat; if (chatPhoto) { @@ -700,6 +702,8 @@ async function getFullChannelInfo( botVerification: botVerification && buildApiBotVerification(botVerification), isPaidReactionAvailable: paidReactionsAvailable, hasScheduledMessages: hasScheduled, + starGiftCount: stargiftsCount, + areStarGiftsAvailable: Boolean(stargiftsAvailable), }, chats, userStatusesById: statusesById, diff --git a/src/api/gramjs/methods/payments.ts b/src/api/gramjs/methods/payments.ts index c8302989e..41d2e2980 100644 --- a/src/api/gramjs/methods/payments.ts +++ b/src/api/gramjs/methods/payments.ts @@ -6,16 +6,16 @@ import type { ApiInputStorePaymentPurpose, ApiPeer, ApiRequestInputInvoice, + ApiRequestInputSavedStarGift, ApiStarGiftRegular, ApiThemeParameters, - ApiUser, } from '../../types'; import { DEBUG } from '../../../config'; import { + buildApiSavedStarGift, buildApiStarGift, buildApiStarGiftAttribute, - buildApiUserStarGift, } from '../apiBuilders/gifts'; import { buildApiBoost, @@ -37,7 +37,12 @@ import { } from '../apiBuilders/payments'; import { buildApiPeerId } from '../apiBuilders/peers'; import { - buildInputInvoice, buildInputPeer, buildInputStorePaymentPurpose, buildInputThemeParams, buildShippingInfo, + buildInputInvoice, + buildInputPeer, + buildInputSavedStarGift, + buildInputStorePaymentPurpose, + buildInputThemeParams, + buildShippingInfo, } from '../gramjsBuilders'; import { deserializeBytes, @@ -440,17 +445,17 @@ export async function fetchStarGifts() { return result.gifts.map(buildApiStarGift).filter((gift): gift is ApiStarGiftRegular => gift.type === 'starGift'); } -export async function fetchUserStarGifts({ - user, +export async function fetchSavedStarGifts({ + peer, offset = '', limit, }: { - user: ApiUser; + peer: ApiPeer; offset?: string; limit?: number; }) { - const result = await invokeRequest(new GramJs.payments.GetUserStarGifts({ - userId: buildInputPeer(user.id, user.accessHash), + const result = await invokeRequest(new GramJs.payments.GetSavedStarGifts({ + peer: buildInputPeer(peer.id, peer.accessHash), offset, limit, })); @@ -459,7 +464,7 @@ export async function fetchUserStarGifts({ return undefined; } - const gifts = result.gifts.map(buildApiUserStarGift); + const gifts = result.gifts.map((g) => buildApiSavedStarGift(g, peer.id)); return { gifts, @@ -468,25 +473,25 @@ export async function fetchUserStarGifts({ } export function saveStarGift({ - messageId, + inputGift, shouldUnsave, }: { - messageId: number; + inputGift: ApiRequestInputSavedStarGift; shouldUnsave?: boolean; }) { return invokeRequest(new GramJs.payments.SaveStarGift({ - msgId: messageId, + stargift: buildInputSavedStarGift(inputGift), unsave: shouldUnsave || undefined, })); } export function convertStarGift({ - messageId, + inputSavedGift, }: { - messageId: number; + inputSavedGift: ApiRequestInputSavedStarGift; }) { return invokeRequest(new GramJs.payments.ConvertStarGift({ - msgId: messageId, + stargift: buildInputSavedStarGift(inputSavedGift), })); } @@ -671,14 +676,14 @@ export async function fetchStarGiftUpgradePreview({ } export function upgradeGift({ - messageId, + inputSavedGift, shouldKeepOriginalDetails, }: { - messageId: number; + inputSavedGift: ApiRequestInputSavedStarGift; shouldKeepOriginalDetails?: true; }) { return invokeRequest(new GramJs.payments.UpgradeStarGift({ - msgId: messageId, + stargift: buildInputSavedStarGift(inputSavedGift), keepOriginalDetails: shouldKeepOriginalDetails, }), { shouldReturnTrue: true, diff --git a/src/api/types/chats.ts b/src/api/types/chats.ts index 66ff41434..dc9df6b5c 100644 --- a/src/api/types/chats.ts +++ b/src/api/types/chats.ts @@ -141,6 +141,8 @@ export interface ApiChatFullInfo { hasPinnedStories?: boolean; isPaidReactionAvailable?: boolean; hasScheduledMessages?: boolean; + starGiftCount?: number; + areStarGiftsAvailable?: boolean; boostsApplied?: number; boostsToUnrestrict?: number; diff --git a/src/api/types/messages.ts b/src/api/types/messages.ts index d422e86f4..79cfd96a0 100644 --- a/src/api/types/messages.ts +++ b/src/api/types/messages.ts @@ -1,18 +1,16 @@ import type { ThreadId, WebPageMediaSize } from '../../types'; import type { ApiWebDocument } from './bots'; import type { ApiGroupCall, PhoneCallAction } from './calls'; -import type { ApiChat, ApiPeerColor } from './chats'; +import type { ApiPeerColor } from './chats'; import type { - ApiInputStorePaymentPurpose, + ApiInputSavedStarGift, ApiLabeledPrice, - ApiPremiumGiftCodeOption, ApiStarGiftRegular, ApiStarGiftUnique, } from './payments'; import type { ApiMessageStoryData, ApiStory, ApiWebPageStickerData, ApiWebPageStoryData, } from './stories'; -import type { ApiUser } from './users'; export interface ApiDimensions { width: number; @@ -207,149 +205,6 @@ export interface ApiPoll { }; } -/* Used for Invoice UI */ -export type ApiInputInvoiceMessage = { - type: 'message'; - chatId: string; - messageId: number; - isExtendedMedia?: boolean; -}; - -export type ApiInputInvoiceSlug = { - type: 'slug'; - slug: string; -}; - -export type ApiInputInvoiceGiveaway = { - type: 'giveaway'; - chatId: string; - additionalChannelIds?: string[]; - isOnlyForNewSubscribers?: boolean; - areWinnersVisible?: boolean; - prizeDescription?: string; - countries?: string[]; - untilDate: number; - currency: string; - amount: number; - option: ApiPremiumGiftCodeOption; -}; - -export type ApiInputInvoiceGiftCode = { - type: 'giftcode'; - userIds: string[]; - boostChannelId?: string; - currency: string; - amount: number; - option: ApiPremiumGiftCodeOption; - message?: ApiFormattedText; -}; - -export type ApiInputInvoiceStars = { - type: 'stars'; - stars: number; - currency: string; - amount: number; -}; - -export type ApiInputInvoiceStarsGift = { - type: 'starsgift'; - userId: string; - stars: number; - currency: string; - amount: number; -}; - -export type ApiInputInvoiceStarGift = { - type: 'stargift'; - shouldHideName?: boolean; - userId: string; - giftId: string; - message?: ApiFormattedText; - shouldUpgrade?: true; -}; - -export type ApiInputInvoiceStarsGiveaway = { - type: 'starsgiveaway'; - chatId: string; - additionalChannelIds?: string[]; - isOnlyForNewSubscribers?: boolean; - areWinnersVisible?: boolean; - prizeDescription?: string; - countries?: string[]; - untilDate: number; - currency: string; - amount: number; - stars: number; - users: number; -}; - -export type ApiInputInvoiceChatInviteSubscription = { - type: 'chatInviteSubscription'; - hash: string; -}; - -export type ApiInputInvoiceStarGiftUpgrade = { - type: 'stargiftUpgrade'; - messageId: number; - shouldKeepOriginalDetails?: true; -}; - -export type ApiInputInvoice = ApiInputInvoiceMessage | ApiInputInvoiceSlug | ApiInputInvoiceGiveaway -| ApiInputInvoiceGiftCode | ApiInputInvoiceStars | ApiInputInvoiceStarsGift | ApiInputInvoiceStarGiftUpgrade -| ApiInputInvoiceStarsGiveaway | ApiInputInvoiceStarGift | ApiInputInvoiceChatInviteSubscription; - -/* Used for Invoice request */ -export type ApiRequestInputInvoiceMessage = { - type: 'message'; - chat: ApiChat; - messageId: number; -}; - -export type ApiRequestInputInvoiceSlug = { - type: 'slug'; - slug: string; -}; - -export type ApiRequestInputInvoiceGiveaway = { - type: 'giveaway'; - purpose: ApiInputStorePaymentPurpose; - option: ApiPremiumGiftCodeOption; -}; - -export type ApiRequestInputInvoiceStars = { - type: 'stars'; - purpose: ApiInputStorePaymentPurpose; -}; - -export type ApiRequestInputInvoiceStarsGiveaway = { - type: 'starsgiveaway'; - purpose: ApiInputStorePaymentPurpose; -}; - -export type ApiRequestInputInvoiceStarGift = { - type: 'stargift'; - shouldHideName?: boolean; - user: ApiUser; - giftId: string; - message?: ApiFormattedText; - shouldUpgrade?: true; -}; - -export type ApiRequestInputInvoiceChatInviteSubscription = { - type: 'chatInviteSubscription'; - hash: string; -}; - -export type ApiRequestInputInvoiceStarGiftUpgrade = { - type: 'stargiftUpgrade'; - messageId: number; - shouldKeepOriginalDetails?: true; -}; - -export type ApiRequestInputInvoice = ApiRequestInputInvoiceMessage | ApiRequestInputInvoiceSlug -| ApiRequestInputInvoiceGiveaway | ApiRequestInputInvoiceStars | ApiRequestInputInvoiceStarsGiveaway -| ApiRequestInputInvoiceChatInviteSubscription | ApiRequestInputInvoiceStarGift | ApiRequestInputInvoiceStarGiftUpgrade; - export interface ApiInvoice { prices: ApiLabeledPrice[]; totalAmount: number; @@ -485,6 +340,10 @@ export interface ApiMessageActionStarGift { isUpgraded?: true; upgradeMsgId?: number; alreadyPaidUpgradeStars?: number; + fromId?: string; + peerId?: string; + savedId?: string; + inputSavedGift?: ApiInputSavedStarGift; } export interface ApiMessageActionStarGiftUnique { @@ -496,6 +355,10 @@ export interface ApiMessageActionStarGiftUnique { gift: ApiStarGiftUnique; canExportAt?: number; transferStars?: number; + fromId?: string; + peerId?: string; + savedId?: string; + inputSavedGift?: ApiInputSavedStarGift; } export interface ApiAction { diff --git a/src/api/types/payments.ts b/src/api/types/payments.ts index 33aa30298..bf62bb3c2 100644 --- a/src/api/types/payments.ts +++ b/src/api/types/payments.ts @@ -1,6 +1,6 @@ import type { PREMIUM_FEATURE_SECTIONS } from '../../config'; import type { ApiWebDocument } from './bots'; -import type { ApiChat } from './chats'; +import type { ApiChat, ApiPeer } from './chats'; import type { ApiDocument, ApiFormattedText, @@ -213,6 +213,7 @@ export interface ApiStarGiftUnique { number: number; ownerId?: string; ownerName?: string; + ownerAddress?: string; issuedCount: number; totalCount: number; attributes: ApiStarGiftAttribute[]; @@ -256,12 +257,14 @@ export interface ApiStarGiftAttributeOriginalDetails { export type ApiStarGiftAttribute = ApiStarGiftAttributeModel | ApiStarGiftAttributePattern | ApiStarGiftAttributeBackdrop | ApiStarGiftAttributeOriginalDetails; -export interface ApiUserStarGift { +export interface ApiSavedStarGift { isNameHidden?: boolean; isUnsaved?: boolean; fromId?: string; date: number; gift: ApiStarGift; + inputGift?: ApiInputSavedStarGift; + savedId?: string; message?: ApiFormattedText; messageId?: number; starsToConvert?: number; @@ -272,6 +275,27 @@ export interface ApiUserStarGift { upgradeMsgId?: number; // Local field, used for Action Message } +export interface ApiInputSavedStarGiftUser { + type: 'user'; + messageId: number; +} + +export interface ApiInputSavedStarGiftChat { + type: 'chat'; + chatId: string; + savedId: string; +} + +export type ApiInputSavedStarGift = ApiInputSavedStarGiftUser | ApiInputSavedStarGiftChat; + +export type ApiRequestInputSavedStarGiftUser = ApiInputSavedStarGiftUser; +export type ApiRequestInputSavedStarGiftChat = { + type: 'chat'; + chat: ApiChat; + savedId: string; +}; +export type ApiRequestInputSavedStarGift = ApiRequestInputSavedStarGiftUser | ApiRequestInputSavedStarGiftChat; + export interface ApiPremiumGiftCodeOption { users: number; months: number; @@ -476,3 +500,146 @@ export interface ApiStarGiveawayOption { } export type ApiPaymentStatus = 'paid' | 'failed' | 'pending' | 'cancelled'; + +/* Used for Invoice UI */ +export type ApiInputInvoiceMessage = { + type: 'message'; + chatId: string; + messageId: number; + isExtendedMedia?: boolean; +}; + +export type ApiInputInvoiceSlug = { + type: 'slug'; + slug: string; +}; + +export type ApiInputInvoiceGiveaway = { + type: 'giveaway'; + chatId: string; + additionalChannelIds?: string[]; + isOnlyForNewSubscribers?: boolean; + areWinnersVisible?: boolean; + prizeDescription?: string; + countries?: string[]; + untilDate: number; + currency: string; + amount: number; + option: ApiPremiumGiftCodeOption; +}; + +export type ApiInputInvoiceGiftCode = { + type: 'giftcode'; + userIds: string[]; + boostChannelId?: string; + currency: string; + amount: number; + option: ApiPremiumGiftCodeOption; + message?: ApiFormattedText; +}; + +export type ApiInputInvoiceStars = { + type: 'stars'; + stars: number; + currency: string; + amount: number; +}; + +export type ApiInputInvoiceStarsGift = { + type: 'starsgift'; + userId: string; + stars: number; + currency: string; + amount: number; +}; + +export type ApiInputInvoiceStarGift = { + type: 'stargift'; + shouldHideName?: boolean; + peerId: string; + giftId: string; + message?: ApiFormattedText; + shouldUpgrade?: true; +}; + +export type ApiInputInvoiceStarsGiveaway = { + type: 'starsgiveaway'; + chatId: string; + additionalChannelIds?: string[]; + isOnlyForNewSubscribers?: boolean; + areWinnersVisible?: boolean; + prizeDescription?: string; + countries?: string[]; + untilDate: number; + currency: string; + amount: number; + stars: number; + users: number; +}; + +export type ApiInputInvoiceChatInviteSubscription = { + type: 'chatInviteSubscription'; + hash: string; +}; + +export type ApiInputInvoiceStarGiftUpgrade = { + type: 'stargiftUpgrade'; + inputSavedGift: ApiInputSavedStarGift; + shouldKeepOriginalDetails?: true; +}; + +export type ApiInputInvoice = ApiInputInvoiceMessage | ApiInputInvoiceSlug | ApiInputInvoiceGiveaway +| ApiInputInvoiceGiftCode | ApiInputInvoiceStars | ApiInputInvoiceStarsGift | ApiInputInvoiceStarGiftUpgrade +| ApiInputInvoiceStarsGiveaway | ApiInputInvoiceStarGift | ApiInputInvoiceChatInviteSubscription; + +/* Used for Invoice request */ +export type ApiRequestInputInvoiceMessage = { + type: 'message'; + chat: ApiChat; + messageId: number; +}; + +export type ApiRequestInputInvoiceSlug = { + type: 'slug'; + slug: string; +}; + +export type ApiRequestInputInvoiceGiveaway = { + type: 'giveaway'; + purpose: ApiInputStorePaymentPurpose; + option: ApiPremiumGiftCodeOption; +}; + +export type ApiRequestInputInvoiceStars = { + type: 'stars'; + purpose: ApiInputStorePaymentPurpose; +}; + +export type ApiRequestInputInvoiceStarsGiveaway = { + type: 'starsgiveaway'; + purpose: ApiInputStorePaymentPurpose; +}; + +export type ApiRequestInputInvoiceStarGift = { + type: 'stargift'; + shouldHideName?: boolean; + peer: ApiPeer; + giftId: string; + message?: ApiFormattedText; + shouldUpgrade?: true; +}; + +export type ApiRequestInputInvoiceChatInviteSubscription = { + type: 'chatInviteSubscription'; + hash: string; +}; + +export type ApiRequestInputInvoiceStarGiftUpgrade = { + type: 'stargiftUpgrade'; + inputSavedGift: ApiRequestInputSavedStarGift; + shouldKeepOriginalDetails?: true; +}; + +export type ApiRequestInputInvoice = ApiRequestInputInvoiceMessage | ApiRequestInputInvoiceSlug +| ApiRequestInputInvoiceGiveaway | ApiRequestInputInvoiceStars | ApiRequestInputInvoiceStarsGiveaway +| ApiRequestInputInvoiceChatInviteSubscription | ApiRequestInputInvoiceStarGift | ApiRequestInputInvoiceStarGiftUpgrade; diff --git a/src/api/types/users.ts b/src/api/types/users.ts index 687332434..c8bfb32db 100644 --- a/src/api/types/users.ts +++ b/src/api/types/users.ts @@ -4,7 +4,7 @@ import type { ApiBusinessIntro, ApiBusinessLocation, ApiBusinessWorkHours } from import type { ApiPeerColor } from './chats'; import type { ApiDocument, ApiPhoto } from './messages'; import type { ApiBotVerification } from './misc'; -import type { ApiUserStarGift } from './payments'; +import type { ApiSavedStarGift } from './payments'; export interface ApiUser { id: string; @@ -89,8 +89,8 @@ export interface ApiUserCommonChats { isFullyLoaded: boolean; } -export interface ApiUserGifts { - gifts: ApiUserStarGift[]; +export interface ApiSavedGifts { + gifts: ApiSavedStarGift[]; nextOffset?: string; } diff --git a/src/assets/localization/fallback.strings b/src/assets/localization/fallback.strings index 5586bf9ea..2b0f7a6dc 100644 --- a/src/assets/localization/fallback.strings +++ b/src/assets/localization/fallback.strings @@ -244,6 +244,7 @@ "SavedMessagesInfo" = "Forward here to save"; "BlockedListNotFound" = "No users found."; "TextCopied" = "Text copied to clipboard."; +"WalletAddressCopied" = "Wallet address copied to clipboard."; "Copy" = "Copy"; "ChatListDeleteAndLeaveGroupConfirmation" = "Are you sure you want to leave and delete {chat}?"; "ChannelLeaveAlertWithName" = "Are you sure you want to leave **{chat}**?"; @@ -1361,6 +1362,7 @@ "StarsGiftHeaderSelf" = "Buy a Gift"; "StarGiftDescription" = "Give {user} gifts that can be kept on the profile or converted to Stars."; "StarGiftDescriptionSelf" = "Buy yourself a gift to add to your profile or reserve for later.\n\nLimited-edition gifts upgraded to collectibles can be gifted to others."; +"StarGiftDescriptionChannel" = "Select gift to show appreciation to **{peer}**."; "GiftLimited" = "limited"; "GiftDiscount" = "-{percent}%"; "GiftSoldCount" = "{count} sold"; @@ -1368,23 +1370,24 @@ "GiftSoldOut" = "sold out"; "GiftMessagePlaceholder" = "Enter Message (Optional)"; "GiftHideMyName" = "Hide My Name"; -"GiftHideNameDescription" = "Hide my name and message from visitors to {profile}'s profile. {receiver} will still see your name and message."; +"GiftHideNameDescription" = "You can hide your name and message from visitors to {receiver}'s profile. {receiver} will still see your name and message."; +"GiftHideNameDescriptionChannel" = "You can hide your name and message from all visitors of this channel except its admins."; "GiftSend" = "Send a Gift for {amount}"; "GiftInfoSent" = "Sent Gift"; "GiftInfoReceived" = "Received Gift"; "GiftInfoTitle" = "Gift"; "GiftInfoDescription_one" = "You can keep this gift in your Profile or convert it to **{amount}** Star."; "GiftInfoDescription_other" = "You can keep this gift in your Profile or convert it to **{amount}** Stars."; -"GiftInfoDescriptionOut_one" = "{user} can keep this gift in profile or convert it to **{amount}** Star."; -"GiftInfoDescriptionOut_other" = "{user} can keep this gift in profile or convert it to **{amount}** Stars."; +"GiftInfoPeerDescriptionOut_one" = "{peer} can keep this gift in profile or convert it to **{amount}** Star."; +"GiftInfoPeerDescriptionOut_other" = "{peer} can keep this gift in profile or convert it to **{amount}** Stars."; "GiftInfoDescriptionUpgrade_one" = "You can keep this gift, upgrade it, or sell it for **{amount}** Star."; "GiftInfoDescriptionUpgrade_other" = "You can keep this gift, upgrade it, or sell it for **{amount}** Stars."; "GiftInfoDescriptionConverted_one" = "You converted this gift to **{amount}** Star."; "GiftInfoDescriptionConverted_other" = "You converted this gift to **{amount}** Stars."; -"GiftInfoDescriptionOutConverted_one" = "{user} converted this gift to **{amount}** Star."; -"GiftInfoDescriptionOutConverted_other" = "{user} converted this gift to **{amount}** Stars."; +"GiftInfoPeerDescriptionOutConverted_one" = "{peer} converted this gift to **{amount}** Star."; +"GiftInfoPeerDescriptionOutConverted_other" = "{peer} converted this gift to **{amount}** Stars."; "GiftInfoDescriptionFreeUpgrade" = "Upgrade this gift for free to turn it to a unique collectible."; -"GiftInfoDescriptionFreeUpgradeOut" = "{user} can turn this gift to a unique collectible"; +"GiftInfoPeerDescriptionFreeUpgradeOut" = "{peer} can turn this gift to a unique collectible"; "GiftInfoDescriptionUpgraded" = "This gift was turned into a unique collectible."; "GiftInfoFrom" = "From"; "GiftInfoDate" = "Date"; @@ -1392,14 +1395,16 @@ "GiftInfoConvert_one" = "Convert to {amount} Star"; "GiftInfoConvert_other" = "Convert to {amount} Stars"; "GiftInfoConvertTitle" = "Convert Gift to Stars"; -"GiftInfoConvertDescription1" = "Do you want to convert this gift from **{user}** to **{amount}**?"; +"GiftInfoPeerConvertDescription" = "Do you want to convert this gift from **{peer}** to **{amount}**?"; "GiftInfoConvertDescription2" = "This action cannot be undone. This will permanently destroy the gift."; "GiftInfoConvertDescriptionPeriod_one" = "Conversion is available for the next **{count} days**."; "GiftInfoConvertDescriptionPeriod_other" = "Conversion is available for the next **{count} days**."; "GiftInfoSaved" = "This gift is visible on your profile. {link}"; +"GiftInfoHidden" = "This gift is hidden. Only you can see it. {link}"; +"GiftInfoChannelSaved" = "This gift is visible in your channel's Gifts. {link}"; +"GiftInfoChannelHidden" = "This gift is hidden from visitors of your channel. {link}"; "GiftInfoSavedHide" = "Hide >"; "GiftInfoSavedShow" = "Show >"; -"GiftInfoHidden" = "This gift is hidden. Only you can see it. {link}"; "GiftInfoAvailability" = "Availability"; "GiftInfoAvailabilityValue_one" = "{count} of {total} left"; "GiftInfoAvailabilityValue_other" = "{count} of {total} left"; @@ -1415,10 +1420,10 @@ "GiftAttributeModel" = "Model"; "GiftAttributeBackdrop" = "Backdrop"; "GiftAttributeSymbol" = "Symbol"; -"GiftInfoOriginalInfo" = "Gifted to {user} on {date}."; -"GiftInfoOriginalInfoSender" = "Gifted by {sender} to {user} on {date}."; -"GiftInfoOriginalInfoText" = "Gifted to {user} on {date} with comment \"{text}\"."; -"GiftInfoOriginalInfoTextSender" = "Gifted by {sender} to {user} on {date} with comment \"{text}\"."; +"GiftInfoPeerOriginalInfo" = "Gifted to {peer} on {date}."; +"GiftInfoPeerOriginalInfoSender" = "Gifted by {sender} to {peer} on {date}."; +"GiftInfoPeerOriginalInfoText" = "Gifted to {peer} on {date} with comment \"{text}\"."; +"GiftInfoPeerOriginalInfoTextSender" = "Gifted by {sender} to {peer} on {date} with comment \"{text}\"."; "GiftInfoStatus" = "Status"; "GiftInfoStatusNonUnique" = "Non-Unique"; "GiftInfoViewUpgraded" = "View Upgraded Gift"; @@ -1431,7 +1436,7 @@ "GiftUpgradeTradeableTitle" = "Tradable"; "GiftUpgradeTradeableDescription" = "Sell or auction your gift on third-party NFT marketplaces."; "GiftUpgradeTitle" = "Make unique"; -"GiftUpgradeText" = "Let {peer} turn your gift into a unique collectible."; +"GiftPeerUpgradeText" = "Let {peer} turn your gift into a unique collectible."; "GiftUpgradeTextOwn" = "Turn your gift into a unique collectible that you can transfer or auction."; "GiftUpgradeKeepDetails" = "Keep sender's name and comment"; "GiftUpgradeButton" = "Upgrade {amount}"; @@ -1440,6 +1445,7 @@ "GiftMakeUnique" = "Make unique for {stars}"; "GiftMakeUniqueAcc" = "Make unique"; "GiftMakeUniqueDescription" = "Enable this to let {user} turn your gift into a unique collectible. {link}"; +"GiftMakeUniqueDescriptionChannel" = "Enable this to let admins of {peer} to turn your gift into a unique collectible. {link}"; "GiftMakeUniqueLink" = "Learn More >"; "StarsAmount" = "⭐️{amount}"; "StarsAmountText_one" = "{amount} Star"; @@ -1457,14 +1463,15 @@ "MiniAppsMoreTabs_other" = "{botName} & {count} Others"; "PrizeCredits2_one" = "Your prize is {count} Star."; "PrizeCredits2_other" = "Your prize is {count} Stars."; -"ActionStarGiftTitle" = "{user} sent you a Gift for {count} Stars"; +"ActionStarGiftPeerTitle" = "{peer} sent you a Gift for {count} Stars"; "ActionStarGiftOutTitle" = "You have sent a gift for {count} Stars"; -"ActionStarGiftOutDescription2_one" = "{user} can display this gift on their profile or convert it to {count} Star."; -"ActionStarGiftOutDescription2_other" = "{user} can display this gift on their profile or convert it to {count} Stars."; +"ActionStarGiftPeerOutDescription_one" = "{peer} can display this gift on their profile or convert it to {count} Star."; +"ActionStarGiftPeerOutDescription_other" = "{peer} can display this gift on their profile or convert it to {count} Stars."; "ActionStarGiftDescription2_one" = "Add this gift to your profile or convert it to {count} Star."; "ActionStarGiftDescription2_other" = "Add this gift to your profile or convert it to {count} Stars."; "ActionStarGiftDisplaying" = "You kept this gift on your profile."; -"ActionStarGiftOutDescriptionUpgrade" = "{user} can turn this gift to a unique collectible."; +"ActionStarGiftChannelDisplaying" = "This gift is displayed to visitors of your channel."; +"ActionStarGiftPeerOutDescriptionUpgrade" = "{peer} can turn this gift to a unique collectible."; "ActionStarGiftDescriptionUpgrade" = "Tap “Unpack” to turn this gift to a unique collectible."; "ActionStarGiftUpgraded" = "This gift was upgraded."; "ActionStarGiftUnpack" = "Unpack"; diff --git a/src/components/common/gift/UserGift.module.scss b/src/components/common/gift/SavedGift.module.scss similarity index 100% rename from src/components/common/gift/UserGift.module.scss rename to src/components/common/gift/SavedGift.module.scss diff --git a/src/components/common/gift/UserGift.tsx b/src/components/common/gift/SavedGift.tsx similarity index 86% rename from src/components/common/gift/UserGift.tsx rename to src/components/common/gift/SavedGift.tsx index 49cbac0fc..88368fa2e 100644 --- a/src/components/common/gift/UserGift.tsx +++ b/src/components/common/gift/SavedGift.tsx @@ -1,9 +1,9 @@ import React, { memo, useMemo, useRef } from '../../../lib/teact/teact'; import { getActions, withGlobal } from '../../../global'; -import type { ApiUser, ApiUserStarGift } from '../../../api/types'; +import type { ApiPeer, ApiSavedStarGift } from '../../../api/types'; -import { selectUser } from '../../../global/selectors'; +import { selectPeer } from '../../../global/selectors'; import { CUSTOM_PEER_HIDDEN } from '../../../util/objects/customPeer'; import { formatIntegerCompact } from '../../../util/textFormat'; import { getGiftAttributes, getStickerFromGift, getTotalGiftAvailability } from '../helpers/gifts'; @@ -19,22 +19,22 @@ import Icon from '../icons/Icon'; import RadialPatternBackground from '../profile/RadialPatternBackground'; import GiftRibbon from './GiftRibbon'; -import styles from './UserGift.module.scss'; +import styles from './SavedGift.module.scss'; type OwnProps = { - userId: string; - gift: ApiUserStarGift; + peerId: string; + gift: ApiSavedStarGift; observeIntersection?: ObserveFn; }; type StateProps = { - fromPeer?: ApiUser; + fromPeer?: ApiPeer; }; const GIFT_STICKER_SIZE = 90; -const UserGift = ({ - userId, +const SavedGift = ({ + peerId, gift, fromPeer, observeIntersection, @@ -50,7 +50,7 @@ const UserGift = ({ const handleClick = useLastCallback(() => { openGiftInfoModal({ - userId, + peerId, gift, }); }); @@ -92,7 +92,7 @@ const UserGift = ({ return (
{radialPatternBackdrop} - + {!radialPatternBackdrop && } ( (global, { gift }): StateProps => { - const fromPeer = gift.fromId ? selectUser(global, gift.fromId) : undefined; + const fromPeer = gift.fromId ? selectPeer(global, gift.fromId) : undefined; return { fromPeer, }; }, -)(UserGift)); +)(SavedGift)); diff --git a/src/components/middle/ActionMessage.tsx b/src/components/middle/ActionMessage.tsx index 8f74c50b3..903dbe094 100644 --- a/src/components/middle/ActionMessage.tsx +++ b/src/components/middle/ActionMessage.tsx @@ -11,7 +11,9 @@ import type { ObserveFn } from '../../hooks/useIntersectionObserver'; import type { FocusDirection, MessageListType, ThreadId } from '../../types'; import type { OnIntersectPinnedMessage } from './hooks/usePinnedMessage'; -import { getChatTitle, getMessageHtmlId, isJoinedChannelMessage } from '../../global/helpers'; +import { + getChatTitle, getMessageHtmlId, getPeerTitle, isJoinedChannelMessage, +} from '../../global/helpers'; import { getMessageReplyInfo } from '../../global/helpers/replies'; import { selectCanPlayAnimatedEmojis, @@ -21,6 +23,7 @@ import { selectGiftStickerForStars, selectIsCurrentUserPremium, selectIsMessageFocused, + selectPeer, selectTabState, selectTheme, selectTopicFromMessage, @@ -86,6 +89,7 @@ type StateProps = { starsGiftSticker?: ApiSticker; canPlayAnimatedEmojis?: boolean; patternColor?: string; + currentUserId?: string; isCurrentUserPremium?: boolean; }; @@ -119,6 +123,7 @@ const ActionMessage: FC = ({ observeIntersectionForLoading, observeIntersectionForPlaying, onIntersectPinnedMessage, + currentUserId, isCurrentUserPremium, }) => { const { @@ -407,16 +412,24 @@ const ActionMessage: FC = ({ } function renderStarGiftUserCaption() { - const targetUser = targetUsers && targetUsers[0]; const starGift = message.content.action?.starGift; - if (!targetUser || !senderUser || !starGift) return undefined; + if (!starGift) return undefined; + const { fromId, peerId } = starGift; - if (message.isOutgoing || (starGift.type === 'starGiftUnique' && starGift.isUpgrade)) { + const fromPeer = fromId ? selectPeer(getGlobal(), fromId) : undefined; + const targetPeer = peerId + ? selectPeer(getGlobal(), peerId) + : starGift.type === 'starGiftUnique' && !message.isOutgoing + ? targetChat : undefined; + + if (targetPeer && targetPeer.id !== currentUserId) { return (
{lang('GiftTo')} - - {targetUser.firstName} + {starGift.type === 'starGift' && ( + + )} + {getPeerTitle(lang, targetPeer)}
); } @@ -424,15 +437,17 @@ const ActionMessage: FC = ({ return (
{lang('GiftFrom')} - - {senderUser.firstName} + {starGift.type === 'starGift' && ( + + )} + {getPeerTitle(lang, fromPeer || senderUser!)}
); } function renderStarGiftUserDescription() { const starGift = message.content.action?.starGift as ApiMessageActionStarGift; - const targetUser = targetUsers && targetUsers[0]?.firstName; + const targetChatTitle = targetChat && getPeerTitle(lang, targetChat); const starGiftMessage = starGift?.message; if (!starGift) return undefined; @@ -442,7 +457,7 @@ const ActionMessage: FC = ({ const amountToConvert = starGift?.starsToConvert; if (starGift.isSaved) { - return lang('ActionStarGiftDisplaying'); + return lang(starGift.savedId ? 'ActionStarGiftChannelDisplaying' : 'ActionStarGiftDisplaying'); } if (starGift.isUpgraded) { @@ -451,24 +466,24 @@ const ActionMessage: FC = ({ if (message.isOutgoing) { if (amountToConvert) { - return lang('ActionStarGiftOutDescription2', { - user: targetUser || 'User', + return lang('ActionStarGiftPeerOutDescription', { + peer: targetChatTitle || 'Someone', count: amountToConvert, }, { withNodes: true, pluralValue: amountToConvert }); } if (starGift.canUpgrade) { - return lang('ActionStarGiftOutDescriptionUpgrade', { - user: targetUser || 'User', + return lang('ActionStarGiftPeerOutDescriptionUpgrade', { + peer: targetChatTitle || 'Someone', }); } } if (starGift.isConverted) { return message.isOutgoing - ? lang('GiftInfoDescriptionOutConverted', { + ? lang('GiftInfoPeerDescriptionOutConverted', { amount: formatInteger(amountToConvert!), - user: targetUser || 'User', + peer: targetChatTitle || 'Chat', }, { pluralValue: amountToConvert!, withNodes: true, @@ -768,6 +783,7 @@ export default memo(withGlobal( noFocusHighlight, }), isCurrentUserPremium: selectIsCurrentUserPremium(global), + currentUserId: global.currentUserId, }; }, )(ActionMessage)); diff --git a/src/components/modals/gift/GiftComposer.tsx b/src/components/modals/gift/GiftComposer.tsx index cf0a78587..1c82eeebb 100644 --- a/src/components/modals/gift/GiftComposer.tsx +++ b/src/components/modals/gift/GiftComposer.tsx @@ -4,13 +4,14 @@ import React, { } from '../../../lib/teact/teact'; import { getActions, withGlobal } from '../../../global'; -import type { ApiMessage, ApiUser } from '../../../api/types'; +import type { ApiMessage, ApiPeer } from '../../../api/types'; import type { ThemeKey } from '../../../types'; import type { GiftOption } from './GiftModal'; import { STARS_CURRENCY_CODE } from '../../../config'; -import { getUserFullName } from '../../../global/helpers'; -import { selectTabState, selectTheme, selectUser } from '../../../global/selectors'; +import { getPeerTitle } from '../../../global/helpers'; +import { isApiPeerUser } from '../../../global/helpers/peers'; +import { selectPeer, selectTabState, selectTheme } from '../../../global/selectors'; import buildClassName from '../../../util/buildClassName'; import buildStyle from '../../../util/buildStyle'; import { formatCurrency } from '../../../util/formatCurrency'; @@ -32,7 +33,7 @@ import styles from './GiftComposer.module.scss'; export type OwnProps = { gift: GiftOption; - userId: string; + peerId: string; }; export type StateProps = { @@ -42,7 +43,7 @@ export type StateProps = { patternColor?: string; customBackground?: string; backgroundColor?: string; - user?: ApiUser; + peer?: ApiPeer; currentUserId?: string; isPaymentFormLoading?: boolean; }; @@ -51,8 +52,8 @@ const LIMIT_DISPLAY_THRESHOLD = 50; function GiftComposer({ gift, - userId, - user, + peerId, + peer, captionLimit, theme, isBackgroundBlurred, @@ -73,6 +74,7 @@ function GiftComposer({ const customBackgroundValue = useCustomBackground(theme, customBackground); const isStarGift = 'id' in gift; + const isPeerUser = peer && isApiPeerUser(peer); const localMessage = useMemo(() => { if (!isStarGift) { @@ -84,7 +86,7 @@ function GiftComposer({ date: Math.floor(Date.now() / 1000), content: { action: { - targetUserIds: [userId], + targetChatId: peerId, mediaType: 'action', text: 'ActionGiftInbound', type: 'giftPremium', @@ -108,7 +110,7 @@ function GiftComposer({ date: Math.floor(Date.now() / 1000), content: { action: { - targetUserIds: [userId], + targetChatId: peerId, mediaType: 'action', text: 'ActionGiftInbound', type: 'starGift', @@ -122,14 +124,17 @@ function GiftComposer({ isNameHidden: shouldHideName, starsToConvert: gift.starsToConvert, canUpgrade: shouldPayForUpgrade || undefined, + alreadyPaidUpgradeStars: shouldPayForUpgrade ? gift.upgradeStars : undefined, isSaved: false, gift, + peerId, + fromId: currentUserId, }, translationValues: ['%action_origin%', '%gift_payment_amount%'], }, }, } satisfies ApiMessage; - }, [currentUserId, gift, giftMessage, isStarGift, shouldHideName, shouldPayForUpgrade, userId]); + }, [currentUserId, gift, giftMessage, isStarGift, shouldHideName, shouldPayForUpgrade, peerId]); const handleGiftMessageChange = useLastCallback((e: ChangeEvent) => { setGiftMessage(e.target.value); @@ -147,14 +152,14 @@ function GiftComposer({ if (!isStarGift) return; openGiftUpgradeModal({ giftId: gift.id, - peerId: userId, + peerId, }); }); const handleMainButtonClick = useLastCallback(() => { if (isStarGift) { sendStarGift({ - userId, + peerId, shouldHideName, gift, message: giftMessage ? { text: giftMessage } : undefined, @@ -165,7 +170,7 @@ function GiftComposer({ openInvoice({ type: 'giftcode', - userIds: [userId], + userIds: [peerId], currency: gift.currency, amount: gift.amount, option: gift, @@ -176,7 +181,7 @@ function GiftComposer({ function renderOptionsSection() { const symbolsLeft = captionLimit ? captionLimit - giftMessage.length : undefined; - const userFullName = getUserFullName(user)!; + const title = getPeerTitle(lang, peer!)!; return (