Stars Giveaway: Create giveaway in groups and channels (#4980)

This commit is contained in:
Alexander Zinchuk 2024-09-24 14:48:44 +02:00
parent 9fa6077fc7
commit 10629eb69a
47 changed files with 1286 additions and 457 deletions

View File

@ -82,6 +82,7 @@ export interface GramJsAppConfig extends LimitsConfig {
upload_premium_speedup_notify_period?: number; upload_premium_speedup_notify_period?: number;
upload_premium_speedup_download?: number; upload_premium_speedup_download?: number;
upload_premium_speedup_upload?: number; upload_premium_speedup_upload?: number;
stars_gifts_enabled?: boolean;
} }
function buildEmojiSounds(appConfig: GramJsAppConfig) { function buildEmojiSounds(appConfig: GramJsAppConfig) {
@ -163,5 +164,6 @@ export function buildAppConfig(json: GramJs.TypeJSONValue, hash: number): ApiApp
bandwidthPremiumDownloadSpeedup: appConfig.upload_premium_speedup_download, bandwidthPremiumDownloadSpeedup: appConfig.upload_premium_speedup_download,
channelRestrictAdsLevelMin: appConfig.channel_restrict_sponsored_level_min, channelRestrictAdsLevelMin: appConfig.channel_restrict_sponsored_level_min,
isChannelRevenueWithdrawalEnabled: appConfig.channel_revenue_withdrawal_enabled, isChannelRevenueWithdrawalEnabled: appConfig.channel_revenue_withdrawal_enabled,
isStarsGiftsEnabled: appConfig.stars_gifts_enabled,
}; };
} }

View File

@ -576,7 +576,7 @@ function buildGiweawayFromMedia(media: GramJs.TypeMessageMedia): ApiGiveaway | u
function buildGiveaway(media: GramJs.MessageMediaGiveaway): ApiGiveaway | undefined { function buildGiveaway(media: GramJs.MessageMediaGiveaway): ApiGiveaway | undefined {
const { const {
channels, months, quantity, untilDate, countriesIso2, onlyNewSubscribers, prizeDescription, channels, months, stars, quantity, untilDate, countriesIso2, onlyNewSubscribers, prizeDescription,
} = media; } = media;
const channelIds = channels.map((channel) => buildApiPeerId(channel, 'channel')); const channelIds = channels.map((channel) => buildApiPeerId(channel, 'channel'));
@ -585,6 +585,7 @@ function buildGiveaway(media: GramJs.MessageMediaGiveaway): ApiGiveaway | undefi
mediaType: 'giveaway', mediaType: 'giveaway',
channelIds, channelIds,
months, months,
stars: stars?.toJSNumber(),
quantity, quantity,
untilDate, untilDate,
countries: countriesIso2, countries: countriesIso2,

View File

@ -608,6 +608,15 @@ function buildAction(
amount = action.winnersCount; amount = action.winnersCount;
pluralValue = action.winnersCount; pluralValue = action.winnersCount;
} }
} else if (action instanceof GramJs.MessageActionPrizeStars) {
type = 'prizeStars';
isUnclaimed = Boolean(action.unclaimed);
if (action.boostPeer) {
targetChatId = getApiChatIdFromMtpPeer(action.boostPeer);
}
text = 'Notification.StarsPrize';
stars = action.stars.toJSNumber();
transactionId = action.transactionId;
} else if (action instanceof GramJs.MessageActionBoostApply) { } else if (action instanceof GramJs.MessageActionBoostApply) {
type = 'chatBoost'; type = 'chatBoost';
if (action.boosts === 1) { if (action.boosts === 1) {

View File

@ -6,9 +6,20 @@ import type {
ApiBoostsStatus, ApiBoostsStatus,
ApiCheckedGiftCode, ApiCheckedGiftCode,
ApiGiveawayInfo, ApiGiveawayInfo,
ApiInvoice, ApiLabeledPrice, ApiMyBoost, ApiPaymentCredentials, ApiInvoice,
ApiPaymentForm, ApiPaymentSavedInfo, ApiPremiumGiftCodeOption, ApiPremiumPromo, ApiPremiumSubscriptionOption, ApiLabeledPrice,
ApiMyBoost,
ApiPaymentCredentials,
ApiPaymentForm,
ApiPaymentSavedInfo,
ApiPremiumGiftCodeOption,
ApiPremiumPromo,
ApiPremiumSubscriptionOption,
ApiPrepaidGiveaway,
ApiPrepaidStarsGiveaway,
ApiReceipt, ApiReceipt,
ApiStarGiveawayOption,
ApiStarsGiveawayWinnerOption,
ApiStarsTransaction, ApiStarsTransaction,
ApiStarsTransactionPeer, ApiStarsTransactionPeer,
ApiStarTopupOption, ApiStarTopupOption,
@ -20,7 +31,7 @@ import { buildApiMessageEntity } from './common';
import { omitVirtualClassFields } from './helpers'; import { omitVirtualClassFields } from './helpers';
import { buildApiDocument, buildApiWebDocument, buildMessageMediaContent } from './messageContent'; import { buildApiDocument, buildApiWebDocument, buildMessageMediaContent } from './messageContent';
import { buildApiPeerId, getApiChatIdFromMtpPeer } from './peers'; import { buildApiPeerId, getApiChatIdFromMtpPeer } from './peers';
import { buildPrepaidGiveaway, buildStatisticsPercentage } from './statistics'; import { buildStatisticsPercentage } from './statistics';
export function buildShippingOptions(shippingOptions: GramJs.ShippingOption[] | undefined) { export function buildShippingOptions(shippingOptions: GramJs.ShippingOption[] | undefined) {
if (!shippingOptions) { if (!shippingOptions) {
@ -265,19 +276,46 @@ export function buildApiPaymentCredentials(credentials: GramJs.PaymentSavedCrede
return credentials.map(({ id, title }) => ({ id, title })); return credentials.map(({ id, title }) => ({ id, title }));
} }
export function buildPrepaidGiveaway(
interaction: GramJs.TypePrepaidGiveaway,
): ApiPrepaidGiveaway | ApiPrepaidStarsGiveaway {
if (interaction instanceof GramJs.PrepaidGiveaway) {
return {
type: 'giveaway',
id: interaction.id.toString(),
date: interaction.date,
months: interaction.months,
quantity: interaction.quantity,
};
}
return {
type: 'starsGiveaway',
id: interaction.id.toString(),
stars: interaction.stars.toJSNumber(),
quantity: interaction.quantity,
boosts: interaction.boosts,
date: interaction.date,
};
}
export function buildApiBoostsStatus(boostStatus: GramJs.premium.BoostsStatus): ApiBoostsStatus { export function buildApiBoostsStatus(boostStatus: GramJs.premium.BoostsStatus): ApiBoostsStatus {
const { const {
level, boostUrl, boosts, myBoost, currentLevelBoosts, nextLevelBoosts, premiumAudience, prepaidGiveaways, level, boostUrl, boosts,
giftBoosts, myBoost, currentLevelBoosts, nextLevelBoosts,
premiumAudience, prepaidGiveaways,
} = boostStatus; } = boostStatus;
return { return {
level, level,
currentLevelBoosts, currentLevelBoosts,
boosts, boosts,
hasMyBoost: Boolean(myBoost), hasMyBoost: Boolean(myBoost),
boostUrl, boostUrl,
giftBoosts,
nextLevelBoosts, nextLevelBoosts,
...(premiumAudience && { premiumSubscribers: buildStatisticsPercentage(premiumAudience) }), ...(premiumAudience && { premiumSubscribers: buildStatisticsPercentage(premiumAudience) }),
...(prepaidGiveaways && { prepaidGiveaways: prepaidGiveaways.map(buildPrepaidGiveaway) }), ...(prepaidGiveaways && { prepaidGiveaways: prepaidGiveaways.map((m) => buildPrepaidGiveaway(m)) }),
}; };
} }
@ -288,6 +326,7 @@ export function buildApiBoost(boost: GramJs.Boost): ApiBoost {
expires, expires,
giveaway, giveaway,
gift, gift,
stars,
} = boost; } = boost;
return { return {
@ -296,6 +335,7 @@ export function buildApiBoost(boost: GramJs.Boost): ApiBoost {
expires, expires,
isFromGiveaway: giveaway, isFromGiveaway: giveaway,
isGift: gift, isGift: gift,
stars: stars?.toJSNumber(),
}; };
} }
@ -342,6 +382,7 @@ export function buildApiGiveawayInfo(info: GramJs.payments.TypeGiveawayInfo): Ap
refunded, refunded,
startDate, startDate,
winnersCount, winnersCount,
starsPrize,
} = info; } = info;
return { return {
@ -353,6 +394,7 @@ export function buildApiGiveawayInfo(info: GramJs.payments.TypeGiveawayInfo): Ap
giftCodeSlug, giftCodeSlug,
isRefunded: refunded, isRefunded: refunded,
isWinner: winner, isWinner: winner,
starsPrize: starsPrize?.toJSNumber(),
}; };
} }
} }
@ -399,6 +441,38 @@ export function buildApiStarsGiftOptions(option: GramJs.StarsGiftOption): ApiSta
}; };
} }
export function buildApiStarsGiveawayWinnersOption(
option: GramJs.StarsGiveawayWinnersOption,
): ApiStarsGiveawayWinnerOption {
const {
default: isDefault, users, perUserStars,
} = option;
return {
isDefault,
users,
perUserStars: perUserStars.toJSNumber(),
};
}
export function buildApiStarsGiveawayOptions(option: GramJs.StarsGiveawayOption): ApiStarGiveawayOption {
const {
extended, default: isDefault, stars, yearlyBoosts, amount, winners, currency,
} = option;
const winnerList = winners?.map((m) => buildApiStarsGiveawayWinnersOption(m)).filter(Boolean);
return {
isExtended: extended,
isDefault,
yearlyBoosts,
stars: stars.toJSNumber(),
amount: amount.toJSNumber(),
currency,
winners: winnerList,
};
}
export function buildApiStarsTransactionPeer(peer: GramJs.TypeStarsTransactionPeer): ApiStarsTransactionPeer { export function buildApiStarsTransactionPeer(peer: GramJs.TypeStarsTransactionPeer): ApiStarsTransactionPeer {
if (peer instanceof GramJs.StarsTransactionPeerAppStore) { if (peer instanceof GramJs.StarsTransactionPeerAppStore) {
return { type: 'appStore' }; return { type: 'appStore' };

View File

@ -8,7 +8,7 @@ import type {
ApiPostStatistics, ApiPostStatistics,
ApiStoryPublicForward, ApiStoryPublicForward,
ChannelMonetizationBalances, ChannelMonetizationBalances,
PrepaidGiveaway, StatisticsGraph, StatisticsGraph,
StatisticsMessageInteractionCounter, StatisticsMessageInteractionCounter,
StatisticsOverviewItem, StatisticsOverviewItem,
StatisticsOverviewPercentage, StatisticsOverviewPercentage,
@ -233,15 +233,6 @@ export function buildStatisticsPercentage(data: GramJs.StatsPercentValue): Stati
}; };
} }
export function buildPrepaidGiveaway(prepaidGiveaway: GramJs.PrepaidGiveaway): PrepaidGiveaway {
return {
id: prepaidGiveaway.id.toString(),
date: prepaidGiveaway.date,
months: prepaidGiveaway.months,
quantity: prepaidGiveaway.quantity,
};
}
function getOverviewPeriod(data: GramJs.StatsDateRangeDays): StatisticsOverviewPeriod { function getOverviewPeriod(data: GramJs.StatsDateRangeDays): StatisticsOverviewPeriod {
return { return {
maxDate: data.maxDate, maxDate: data.maxDate,

View File

@ -568,6 +568,23 @@ GramJs.TypeInputStorePaymentPurpose {
const randomId = generateRandomBigInt(); const randomId = generateRandomBigInt();
if (purpose.type === 'starsgiveaway') {
return new GramJs.InputStorePaymentStarsGiveaway({
boostPeer: buildInputPeer(purpose.chat.id, purpose.chat.accessHash),
additionalPeers: purpose.additionalChannels?.map((chat) => buildInputPeer(chat.id, chat.accessHash)),
stars: BigInt(purpose.stars!),
countriesIso2: purpose.countries,
prizeDescription: purpose.prizeDescription,
onlyNewSubscribers: purpose.isOnlyForNewSubscribers || undefined,
winnersAreVisible: purpose.areWinnersVisible || undefined,
untilDate: purpose.untilDate,
currency: purpose.currency,
amount: BigInt(purpose.amount),
users: purpose.users,
randomId,
});
}
return new GramJs.InputStorePaymentPremiumGiveaway({ return new GramJs.InputStorePaymentPremiumGiveaway({
boostPeer: buildInputPeer(purpose.chat.id, purpose.chat.accessHash), boostPeer: buildInputPeer(purpose.chat.id, purpose.chat.accessHash),
additionalPeers: purpose.additionalChannels?.map((chat) => buildInputPeer(chat.id, chat.accessHash)), additionalPeers: purpose.additionalChannels?.map((chat) => buildInputPeer(chat.id, chat.accessHash)),
@ -613,6 +630,13 @@ export function buildInputInvoice(invoice: ApiRequestInputInvoice) {
}); });
} }
case 'starsgiveaway': {
const purpose = buildInputStorePaymentPurpose(invoice.purpose);
return new GramJs.InputInvoiceStars({
purpose,
});
}
case 'giveaway': case 'giveaway':
default: { default: {
const purpose = buildInputStorePaymentPurpose(invoice.purpose); const purpose = buildInputStorePaymentPurpose(invoice.purpose);

View File

@ -17,7 +17,9 @@ import {
buildApiPaymentForm, buildApiPaymentForm,
buildApiPremiumGiftCodeOption, buildApiPremiumGiftCodeOption,
buildApiPremiumPromo, buildApiPremiumPromo,
buildApiReceipt, buildApiStarsGiftOptions, buildApiReceipt,
buildApiStarsGiftOptions,
buildApiStarsGiveawayOptions,
buildApiStarsTransaction, buildApiStarsTransaction,
buildApiStarTopupOption, buildApiStarTopupOption,
buildShippingOptions, buildShippingOptions,
@ -376,6 +378,16 @@ export async function getStarsGiftOptions({
return result.map(buildApiStarsGiftOptions); return result.map(buildApiStarsGiftOptions);
} }
export async function fetchStarsGiveawayOptions() {
const result = await invokeRequest(new GramJs.payments.GetStarsGiveawayOptions());
if (!result) {
return undefined;
}
return result.map(buildApiStarsGiveawayOptions);
}
export function launchPrepaidGiveaway({ export function launchPrepaidGiveaway({
chat, chat,
giveawayId, giveawayId,

View File

@ -248,8 +248,23 @@ export type ApiInputInvoiceStarsGift = {
amount: number; amount: number;
}; };
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 ApiInputInvoice = ApiInputInvoiceMessage | ApiInputInvoiceSlug | ApiInputInvoiceGiveaway export type ApiInputInvoice = ApiInputInvoiceMessage | ApiInputInvoiceSlug | ApiInputInvoiceGiveaway
| ApiInputInvoiceGiftCode | ApiInputInvoiceStarsGift | ApiInputInvoiceStars; | ApiInputInvoiceGiftCode | ApiInputInvoiceStarsGift | ApiInputInvoiceStars | ApiInputInvoiceStarsGiveaway;
/* Used for Invoice request */ /* Used for Invoice request */
export type ApiRequestInputInvoiceMessage = { export type ApiRequestInputInvoiceMessage = {
@ -274,8 +289,13 @@ export type ApiRequestInputInvoiceStars = {
purpose: ApiInputStorePaymentPurpose; purpose: ApiInputStorePaymentPurpose;
}; };
export type ApiRequestInputInvoiceStarsGiveaway = {
type: 'starsgiveaway';
purpose: ApiInputStorePaymentPurpose;
};
export type ApiRequestInputInvoice = ApiRequestInputInvoiceMessage | ApiRequestInputInvoiceSlug export type ApiRequestInputInvoice = ApiRequestInputInvoiceMessage | ApiRequestInputInvoiceSlug
| ApiRequestInputInvoiceGiveaway | ApiRequestInputInvoiceStars; | ApiRequestInputInvoiceGiveaway | ApiRequestInputInvoiceStars | ApiRequestInputInvoiceStarsGiveaway;
export interface ApiInvoice { export interface ApiInvoice {
mediaType: 'invoice'; mediaType: 'invoice';
@ -351,7 +371,8 @@ export type ApiGame = {
export type ApiGiveaway = { export type ApiGiveaway = {
mediaType: 'giveaway'; mediaType: 'giveaway';
quantity: number; quantity: number;
months: number; months?: number;
stars?: number;
untilDate: number; untilDate: number;
isOnlyForNewSubscribers?: true; isOnlyForNewSubscribers?: true;
countries?: string[]; countries?: string[];
@ -361,7 +382,8 @@ export type ApiGiveaway = {
export type ApiGiveawayResults = { export type ApiGiveawayResults = {
mediaType: 'giveawayResults'; mediaType: 'giveawayResults';
months: number; months?: number;
stars?: number;
untilDate: number; untilDate: number;
isRefunded?: true; isRefunded?: true;
isOnlyForNewSubscribers?: true; isOnlyForNewSubscribers?: true;
@ -400,6 +422,7 @@ export interface ApiAction {
| 'giftStars' | 'giftStars'
| 'giftPremium' | 'giftPremium'
| 'giftCode' | 'giftCode'
| 'prizeStars'
| 'other'; | 'other';
photo?: ApiPhoto; photo?: ApiPhoto;
amount?: number; amount?: number;

View File

@ -211,6 +211,7 @@ export interface ApiAppConfig {
bandwidthPremiumDownloadSpeedup?: number; bandwidthPremiumDownloadSpeedup?: number;
channelRestrictAdsLevelMin?: number; channelRestrictAdsLevelMin?: number;
isChannelRevenueWithdrawalEnabled?: boolean; isChannelRevenueWithdrawalEnabled?: boolean;
isStarsGiftsEnabled?: boolean;
} }
export interface ApiConfig { export interface ApiConfig {

View File

@ -5,7 +5,7 @@ import type { ApiChat } from './chats';
import type { import type {
ApiDocument, ApiMessageEntity, ApiPaymentCredentials, BoughtPaidMedia, ApiDocument, ApiMessageEntity, ApiPaymentCredentials, BoughtPaidMedia,
} from './messages'; } from './messages';
import type { PrepaidGiveaway, StatisticsOverviewPercentage } from './statistics'; import type { StatisticsOverviewPercentage } from './statistics';
import type { ApiUser } from './users'; import type { ApiUser } from './users';
export interface ApiShippingAddress { export interface ApiShippingAddress {
@ -149,8 +149,23 @@ export type ApiInputStorePaymentStarsGift = {
amount: number; amount: number;
}; };
export type ApiInputStorePaymentStarsGiveaway = {
type: 'starsgiveaway';
isOnlyForNewSubscribers?: boolean;
areWinnersVisible?: boolean;
chat: ApiChat;
additionalChannels?: ApiChat[];
stars?: number;
countries?: string[];
prizeDescription?: string;
untilDate: number;
currency: string;
amount: number;
users: number;
};
export type ApiInputStorePaymentPurpose = ApiInputStorePaymentGiveaway | ApiInputStorePaymentGiftcode | export type ApiInputStorePaymentPurpose = ApiInputStorePaymentGiveaway | ApiInputStorePaymentGiftcode |
ApiInputStorePaymentStarsTopup | ApiInputStorePaymentStarsGift; ApiInputStorePaymentStarsTopup | ApiInputStorePaymentStarsGift | ApiInputStorePaymentStarsGiveaway;
export interface ApiPremiumGiftCodeOption { export interface ApiPremiumGiftCodeOption {
users: number; users: number;
@ -159,6 +174,25 @@ export interface ApiPremiumGiftCodeOption {
amount: number; amount: number;
} }
export interface ApiPrepaidGiveaway {
type: 'giveaway';
id: string;
months: number;
quantity: number;
date: number;
}
export type ApiPrepaidStarsGiveaway = {
type: 'starsGiveaway';
id: string;
stars: number;
quantity: number;
boosts: number;
date: number;
};
export type ApiTypePrepaidGiveaway = ApiPrepaidGiveaway | ApiPrepaidStarsGiveaway;
export type ApiBoostsStatus = { export type ApiBoostsStatus = {
level: number; level: number;
currentLevelBoosts: number; currentLevelBoosts: number;
@ -166,8 +200,9 @@ export type ApiBoostsStatus = {
nextLevelBoosts?: number; nextLevelBoosts?: number;
hasMyBoost?: boolean; hasMyBoost?: boolean;
boostUrl: string; boostUrl: string;
giftBoosts?: number;
premiumSubscribers?: StatisticsOverviewPercentage; premiumSubscribers?: StatisticsOverviewPercentage;
prepaidGiveaways?: PrepaidGiveaway[]; prepaidGiveaways?: ApiTypePrepaidGiveaway[];
}; };
export type ApiMyBoost = { export type ApiMyBoost = {
@ -184,6 +219,7 @@ export type ApiBoost = {
expires: number; expires: number;
isFromGiveaway?: boolean; isFromGiveaway?: boolean;
isGift?: boolean; isGift?: boolean;
stars?: number;
}; };
export type ApiGiveawayInfoActive = { export type ApiGiveawayInfoActive = {
@ -201,10 +237,11 @@ export type ApiGiveawayInfoResults = {
isWinner?: true; isWinner?: true;
isRefunded?: true; isRefunded?: true;
startDate: number; startDate: number;
starsPrize?: number;
finishDate: number; finishDate: number;
giftCodeSlug?: string; giftCodeSlug?: string;
winnersCount: number; winnersCount: number;
activatedCount: number; activatedCount?: number;
}; };
export type ApiGiveawayInfo = ApiGiveawayInfoActive | ApiGiveawayInfoResults; export type ApiGiveawayInfo = ApiGiveawayInfoActive | ApiGiveawayInfoResults;
@ -219,13 +256,6 @@ export type ApiCheckedGiftCode = {
usedAt?: number; usedAt?: number;
}; };
export interface ApiPrepaidGiveaway {
id: string;
months: number;
quantity: number;
date: number;
}
export interface ApiStarsTransactionPeerUnsupported { export interface ApiStarsTransactionPeerUnsupported {
type: 'unsupported'; type: 'unsupported';
} }
@ -271,6 +301,7 @@ export interface ApiStarsTransaction {
stars: number; stars: number;
isRefund?: true; isRefund?: true;
isGift?: true; isGift?: true;
isPrizeStars?: true;
isMyGift?: true; // Used only for outgoing star gift messages isMyGift?: true; // Used only for outgoing star gift messages
hasFailed?: true; hasFailed?: true;
isPending?: true; isPending?: true;
@ -287,3 +318,19 @@ export interface ApiStarTopupOption {
currency: string; currency: string;
amount: number; amount: number;
} }
export interface ApiStarsGiveawayWinnerOption {
isDefault?: true;
users: number;
perUserStars: number;
}
export interface ApiStarGiveawayOption {
isExtended?: true;
isDefault?: true;
stars: number;
yearlyBoosts: number;
currency: string;
amount: number;
winners: ApiStarsGiveawayWinnerOption[];
}

View File

@ -1,4 +1,5 @@
import type { ApiChat } from './chats'; import type { ApiChat } from './chats';
import type { ApiTypePrepaidGiveaway } from './payments';
export interface ApiChannelStatistics { export interface ApiChannelStatistics {
growthGraph?: StatisticsGraph | string; growthGraph?: StatisticsGraph | string;
@ -61,7 +62,7 @@ export interface ApiBoostStatistics {
boosts: number; boosts: number;
premiumSubscribers: StatisticsOverviewPercentage; premiumSubscribers: StatisticsOverviewPercentage;
remainingBoosts: number; remainingBoosts: number;
prepaidGiveaways: PrepaidGiveaway[]; prepaidGiveaways: ApiTypePrepaidGiveaway[];
} }
export interface ApiMessagePublicForward { export interface ApiMessagePublicForward {
@ -115,13 +116,6 @@ export interface StatisticsOverviewPercentage {
percentage: string; percentage: string;
} }
export interface PrepaidGiveaway {
id: string;
months: number;
quantity: number;
date: number;
}
export interface StatisticsOverviewPeriod { export interface StatisticsOverviewPeriod {
maxDate: number; maxDate: number;
minDate: number; minDate: number;

View File

@ -1283,3 +1283,4 @@
"CreditsBoxHistoryEntryGiftOutAbout" = "With Stars, {user} will be able to unlock content and services on Telegram. {link}" "CreditsBoxHistoryEntryGiftOutAbout" = "With Stars, {user} will be able to unlock content and services on Telegram. {link}"
"CreditsBoxOutAbout" = "Review the {link} for Stars." "CreditsBoxOutAbout" = "Review the {link} for Stars."
"GiftStarsOutgoing" = "With Stars, {user} will be able to unlock content and services on Telegram." "GiftStarsOutgoing" = "With Stars, {user} will be able to unlock content and services on Telegram."
"PrizeCredits" = "Your prize is {count} Stars."

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 504 KiB

View File

@ -80,7 +80,7 @@ const FullNameTitle: FC<OwnProps> = ({
const specialTitle = useMemo(() => { const specialTitle = useMemo(() => {
if (customPeer) { if (customPeer) {
return lang(customPeer.titleKey); return lang(customPeer.titleKey, customPeer.titleValue, 'i');
} }
if (isSavedMessages) { if (isSavedMessages) {

View File

@ -91,6 +91,11 @@ export function renderActionMessageText(
.replace('un2', '%action_origin%') .replace('un2', '%action_origin%')
.replace(/\*\*/g, ''); .replace(/\*\*/g, '');
} }
if (translationKey === 'BoostingReceivedPrizeFrom') {
unprocessed = unprocessed
.replace('**%s**', '%target_chat%')
.replace(/\*\*/g, '');
}
let processed: TextPart[]; let processed: TextPart[];
if (unprocessed.includes('%star_target_user%')) { if (unprocessed.includes('%star_target_user%')) {

View File

@ -569,10 +569,10 @@ const Main = ({
/> />
<AttachBotRecipientPicker requestedAttachBotInChat={requestedAttachBotInChat} /> <AttachBotRecipientPicker requestedAttachBotInChat={requestedAttachBotInChat} />
<MessageListHistoryHandler /> <MessageListHistoryHandler />
{isPremiumModalOpen && <PremiumMainModal isOpen={isPremiumModalOpen} />} <PremiumMainModal isOpen={isPremiumModalOpen} />
{isGiveawayModalOpen && <GiveawayModal isOpen={isGiveawayModalOpen} />} <GiveawayModal isOpen={isGiveawayModalOpen} />
{isPremiumGiftingPickerModal && <PremiumGiftingPickerModal isOpen={isPremiumGiftingPickerModal} />} <PremiumGiftingPickerModal isOpen={isPremiumGiftingPickerModal} />
{isStarsGiftingPickerModal && <StarsGiftingPickerModal isOpen={isStarsGiftingPickerModal} />} <StarsGiftingPickerModal isOpen={isStarsGiftingPickerModal} />
<PremiumLimitReachedModal limit={limitReached} /> <PremiumLimitReachedModal limit={limitReached} />
<PaymentModal isOpen={isPaymentModalOpen} onClose={closePaymentModal} /> <PaymentModal isOpen={isPaymentModalOpen} onClose={closePaymentModal} />
<ReceiptModal isOpen={isReceiptModalOpen} onClose={clearReceipt} /> <ReceiptModal isOpen={isReceiptModalOpen} onClose={clearReceipt} />

View File

@ -114,6 +114,7 @@
.options { .options {
width: 100%; width: 100%;
padding: 0 0.25rem;
} }
.giveawayTitle { .giveawayTitle {
@ -133,6 +134,10 @@
@include mixins.adapt-margin-to-scrollbar(1rem); @include mixins.adapt-margin-to-scrollbar(1rem);
} }
.starSubscription {
margin-top: 0;
}
.subscriptionOption { .subscriptionOption {
margin-bottom: 0; margin-bottom: 0;
padding-inline: 3.5rem 1rem; padding-inline: 3.5rem 1rem;
@ -142,10 +147,10 @@
.status { .status {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 1rem; gap: 0.8125rem;
justify-content: space-between; justify-content: space-between;
width: 100%; width: 100%;
padding: 0 0.375rem 0 1.125rem; padding: 0 0.375rem 0 1rem;
margin-bottom: 1.3125rem; margin-bottom: 1.3125rem;
} }
@ -263,7 +268,8 @@
} }
.addChannel { .addChannel {
margin-inline-start: initial !important; margin-inline-end: 1.375rem !important;
margin-inline-start: 0.3125rem !important;
} }
.removeChannel { .removeChannel {
@ -272,6 +278,10 @@
padding: 0.5rem; padding: 0.5rem;
} }
.starOptions {
padding: 0.8125rem;
}
@media (max-width: 600px) { @media (max-width: 600px) {
.root :global(.modal-dialog) { .root :global(.modal-dialog) {
width: 100%; width: 100%;

View File

@ -6,7 +6,13 @@ import React, {
import { getActions, getGlobal, withGlobal } from '../../../global'; import { getActions, getGlobal, withGlobal } from '../../../global';
import type { import type {
ApiCountry, ApiPremiumGiftCodeOption, ApiPrepaidGiveaway, ApiUser, ApiCountry,
ApiPremiumGiftCodeOption,
ApiPrepaidGiveaway,
ApiPrepaidStarsGiveaway,
ApiStarGiveawayOption,
ApiTypePrepaidGiveaway,
ApiUser,
} from '../../../api/types'; } from '../../../api/types';
import { import {
@ -22,6 +28,7 @@ import {
} from '../../../global/selectors'; } from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import { formatDateTimeToString } from '../../../util/dates/dateFormat'; import { formatDateTimeToString } from '../../../util/dates/dateFormat';
import { unique } from '../../../util/iteratees';
import renderText from '../../common/helpers/renderText'; import renderText from '../../common/helpers/renderText';
import useFlag from '../../../hooks/useFlag'; import useFlag from '../../../hooks/useFlag';
@ -32,6 +39,7 @@ import CalendarModal from '../../common/CalendarModal';
import CountryPickerModal from '../../common/CountryPickerModal'; import CountryPickerModal from '../../common/CountryPickerModal';
import GroupChatInfo from '../../common/GroupChatInfo'; import GroupChatInfo from '../../common/GroupChatInfo';
import Icon from '../../common/icons/Icon'; import Icon from '../../common/icons/Icon';
import StarTopupOptionList from '../../modals/stars/StarTopupOptionList';
import Button from '../../ui/Button'; import Button from '../../ui/Button';
import ConfirmDialog from '../../ui/ConfirmDialog'; import ConfirmDialog from '../../ui/ConfirmDialog';
import InputText from '../../ui/InputText'; import InputText from '../../ui/InputText';
@ -51,7 +59,7 @@ import styles from './GiveawayModal.module.scss';
import GiftBlueRound from '../../../assets/premium/GiftBlueRound.svg'; import GiftBlueRound from '../../../assets/premium/GiftBlueRound.svg';
import GiftGreenRound from '../../../assets/premium/GiftGreenRound.svg'; import GiftGreenRound from '../../../assets/premium/GiftGreenRound.svg';
import GiftRedRound from '../../../assets/premium/GiftRedRound.svg'; import GiftRedRound from '../../../assets/premium/GiftRedRound.svg';
import GiveawayUsersRound from '../../../assets/premium/GiveawayUsersRound.svg'; import GiftStar from '../../../assets/premium/GiftStar.svg';
import PremiumLogo from '../../../assets/premium/PremiumLogo.svg'; import PremiumLogo from '../../../assets/premium/PremiumLogo.svg';
export type OwnProps = { export type OwnProps = {
@ -69,13 +77,15 @@ type StateProps = {
giveawayBoostPerPremiumLimit?: number; giveawayBoostPerPremiumLimit?: number;
userSelectionLimit?: number; userSelectionLimit?: number;
countryList: ApiCountry[]; countryList: ApiCountry[];
prepaidGiveaway?: ApiPrepaidGiveaway; prepaidGiveaway?: ApiTypePrepaidGiveaway;
countrySelectionLimit: number | undefined; countrySelectionLimit: number | undefined;
isChannel?: boolean; isChannel?: boolean;
isStarsGiftsEnabled?: boolean;
starsGiftOptions?: ApiStarGiveawayOption[] | undefined;
}; };
type GiveawayAction = 'createRandomlyUsers' | 'createSpecificUsers'; type GiveawayAction = 'createPremiumGiveaway' | 'createStarsGiveaway';
type ApiGiveawayType = 'random_users' | 'specific_users'; type ApiGiveawayType = 'premium_giveaway' | 'stars_giveaway';
type SubscribersType = 'all' | 'new'; type SubscribersType = 'all' | 'new';
interface TypeOption { interface TypeOption {
@ -110,12 +120,14 @@ const GiveawayModal: FC<OwnProps & StateProps> = ({
prepaidGiveaway, prepaidGiveaway,
countrySelectionLimit = GIVEAWAY_MAX_ADDITIONAL_COUNTRIES, countrySelectionLimit = GIVEAWAY_MAX_ADDITIONAL_COUNTRIES,
userSelectionLimit = GIVEAWAY_MAX_ADDITIONAL_USERS, userSelectionLimit = GIVEAWAY_MAX_ADDITIONAL_USERS,
isStarsGiftsEnabled,
starsGiftOptions,
}) => { }) => {
// eslint-disable-next-line no-null/no-null // eslint-disable-next-line no-null/no-null
const dialogRef = useRef<HTMLDivElement>(null); const dialogRef = useRef<HTMLDivElement>(null);
const { const {
closeGiveawayModal, openInvoice, openPremiumModal, closeGiveawayModal, openInvoice, openPremiumModal,
launchPrepaidGiveaway, launchPrepaidGiveaway, launchPrepaidStarsGiveaway,
} = getActions(); } = getActions();
const lang = useOldLang(); const lang = useOldLang();
@ -126,28 +138,33 @@ const GiveawayModal: FC<OwnProps & StateProps> = ({
const [isChannelPickerModalOpen, openChannelPickerModal, closeChannelPickerModal] = useFlag(); const [isChannelPickerModalOpen, openChannelPickerModal, closeChannelPickerModal] = useFlag();
const TYPE_OPTIONS: TypeOption[] = [{ const TYPE_OPTIONS: TypeOption[] = [{
name: 'BoostingCreateGiveaway', name: 'Premium.Title',
text: 'BoostingWinnersRandomly', text: 'BoostingWinnersRandomly',
value: 'random_users', value: 'premium_giveaway',
img: GiftBlueRound, img: GiftBlueRound,
actions: 'createRandomlyUsers', actions: 'createPremiumGiveaway',
isLink: false,
}, {
name: 'BoostingAwardSpecificUsers',
text: 'BoostingSelectRecipients',
value: 'specific_users',
img: GiveawayUsersRound,
actions: 'createSpecificUsers',
isLink: true, isLink: true,
onClickAction: () => { onClickAction: () => {
openUserPickerModal(); openUserPickerModal();
}, },
}]; }];
if (isStarsGiftsEnabled) {
TYPE_OPTIONS.push({
name: 'TelegramStars',
text: 'BoostingWinnersRandomly',
value: 'stars_giveaway',
img: GiftStar,
actions: 'createStarsGiveaway',
isLink: false,
});
}
const [customExpireDate, setCustomExpireDate] = useState<number>(Date.now() + DEFAULT_CUSTOM_EXPIRE_DATE); const [customExpireDate, setCustomExpireDate] = useState<number>(Date.now() + DEFAULT_CUSTOM_EXPIRE_DATE);
const [isHeaderHidden, setHeaderHidden] = useState(true); const [isHeaderHidden, setHeaderHidden] = useState(true);
const [selectedRandomUserCount, setSelectedRandomUserCount] = useState<number>(DEFAULT_BOOST_COUNT); const [selectedRandomUserCount, setSelectedRandomUserCount] = useState<number>(DEFAULT_BOOST_COUNT);
const [selectedGiveawayOption, setGiveawayOption] = useState<ApiGiveawayType>(TYPE_OPTIONS[0].value); const [selectedGiveawayOption, setGiveawayOption] = useState<ApiGiveawayType>(TYPE_OPTIONS[0].value);
const [selectedStarOption, setSelectedStarOption] = useState<ApiStarGiveawayOption | undefined>();
const [selectedSubscriberOption, setSelectedSubscriberOption] = useState<SubscribersType>('all'); const [selectedSubscriberOption, setSelectedSubscriberOption] = useState<SubscribersType>('all');
const [selectedMonthOption, setSelectedMonthOption] = useState<number | undefined>(); const [selectedMonthOption, setSelectedMonthOption] = useState<number | undefined>();
const [selectedUserIds, setSelectedUserIds] = useState<string[]>([]); const [selectedUserIds, setSelectedUserIds] = useState<string[]>([]);
@ -157,10 +174,16 @@ const GiveawayModal: FC<OwnProps & StateProps> = ({
const [shouldShowPrizes, setShouldShowPrizes] = useState<boolean>(false); const [shouldShowPrizes, setShouldShowPrizes] = useState<boolean>(false);
const [prizeDescription, setPrizeDescription] = useState<string | undefined>(undefined); const [prizeDescription, setPrizeDescription] = useState<string | undefined>(undefined);
const [dataPrepaidGiveaway, setDataPrepaidGiveaway] = useState<ApiPrepaidGiveaway | undefined>(undefined); const [dataPrepaidGiveaway, setDataPrepaidGiveaway] = useState<ApiPrepaidGiveaway | undefined>(undefined);
const [
dataStarsPrepaidGiveaway, setDataStarsPrepaidGiveaway,
] = useState<ApiPrepaidStarsGiveaway | undefined>(undefined);
const isRandomUsers = selectedGiveawayOption === 'random_users'; const isPremiumGiveaway = selectedGiveawayOption === 'premium_giveaway';
const selectedUserCount = isRandomUsers ? selectedRandomUserCount : selectedUserIds.length; const isStarsGiveaway = selectedGiveawayOption === 'stars_giveaway';
const selectedUserCount = isPremiumGiveaway
&& !selectedUserIds.length ? selectedRandomUserCount : selectedUserIds.length;
const boostQuantity = selectedUserCount * giveawayBoostPerPremiumLimit; const boostQuantity = selectedUserCount * giveawayBoostPerPremiumLimit;
const boostStarsQuantity = selectedStarOption?.yearlyBoosts;
const SUBSCRIBER_OPTIONS = useMemo(() => [ const SUBSCRIBER_OPTIONS = useMemo(() => [
{ {
@ -180,44 +203,65 @@ const GiveawayModal: FC<OwnProps & StateProps> = ({
], [isChannel, lang, selectedCountryIds]); ], [isChannel, lang, selectedCountryIds]);
const monthQuantity = lang('Months', selectedMonthOption); const monthQuantity = lang('Months', selectedMonthOption);
const isStarsPrepaidGiveaway = prepaidGiveaway?.type === 'starsGiveaway';
const isPremiumPrepaidGiveaway = prepaidGiveaway?.type === 'giveaway';
const selectedGift = useMemo(() => { const selectedGift = useMemo(() => {
return gifts!.find((gift) => gift.months === selectedMonthOption && gift.users === selectedUserCount); return gifts?.find((gift) => gift.months === selectedMonthOption && gift.users === selectedUserCount);
}, [gifts, selectedMonthOption, selectedUserCount]); }, [gifts, selectedMonthOption, selectedUserCount]);
const selectedStarsGift = useMemo(() => {
return starsGiftOptions?.find((gift) => {
return isStarsPrepaidGiveaway && gift.stars === (dataStarsPrepaidGiveaway?.stars);
});
}, [dataStarsPrepaidGiveaway, starsGiftOptions, isStarsPrepaidGiveaway]);
const filteredGifts = useMemo(() => { const filteredGifts = useMemo(() => {
return gifts?.filter((gift) => gift.users === selectedUserCount); return gifts?.filter((gift) => gift.users === selectedUserCount);
}, [gifts, selectedUserCount]); }, [gifts, selectedUserCount]);
const fullMonthlyAmount = useMemo(() => { const fullMonthlyAmount = useMemo(() => {
if (!filteredGifts?.length) { const basicGift = filteredGifts?.reduce((acc, gift) => {
return undefined;
}
const basicGift = filteredGifts.reduce((acc, gift) => {
return gift.amount < acc.amount ? gift : acc; return gift.amount < acc.amount ? gift : acc;
}); }, filteredGifts[0]);
return Math.floor(basicGift.amount / basicGift.months); return basicGift && Math.floor(basicGift.amount / basicGift.months);
}, [filteredGifts]); }, [filteredGifts]);
const userCountOptions = useMemo(() => { const userCountOptions = useMemo(() => {
const uniqueUserCounts = new Set(gifts?.map((gift) => gift.users)); return unique((gifts?.map((winner) => winner.users) || [])).sort((a, b) => a - b);
return Array.from(uniqueUserCounts).sort((a, b) => a - b);
}, [gifts]); }, [gifts]);
useEffect(() => { const winnerCountOptions = useMemo(() => {
if (isOpen) { return unique((selectedStarOption?.winners?.map((winner) => winner.users) || [])).sort((a, b) => a - b);
setSelectedMonthOption(prepaidGiveaway ? prepaidGiveaway.months : gifts?.[0].months); }, [selectedStarOption]);
}
}, [gifts, isOpen, prepaidGiveaway]);
useEffect(() => { useEffect(() => {
if (prepaidGiveaway) { if (isOpen && gifts?.length && !isStarsPrepaidGiveaway) {
setSelectedMonthOption(gifts?.[0].months);
}
}, [isOpen, gifts, isStarsPrepaidGiveaway]);
useEffect(() => {
if (isOpen && starsGiftOptions?.length && !isPremiumPrepaidGiveaway) {
setSelectedStarOption(starsGiftOptions?.[0]);
}
}, [isOpen, starsGiftOptions, isPremiumPrepaidGiveaway]);
useEffect(() => {
if (isOpen && isStarsPrepaidGiveaway) {
setSelectedRandomUserCount(prepaidGiveaway.quantity);
setDataStarsPrepaidGiveaway(prepaidGiveaway);
}
}, [isOpen, isStarsPrepaidGiveaway, prepaidGiveaway]);
useEffect(() => {
if (isOpen && isPremiumPrepaidGiveaway) {
setSelectedRandomUserCount(prepaidGiveaway.quantity); setSelectedRandomUserCount(prepaidGiveaway.quantity);
setDataPrepaidGiveaway(prepaidGiveaway); setDataPrepaidGiveaway(prepaidGiveaway);
setSelectedMonthOption(prepaidGiveaway.months);
} }
}, [prepaidGiveaway]); }, [isOpen, isPremiumPrepaidGiveaway, prepaidGiveaway]);
useEffect(() => { useEffect(() => {
if (selectedMemberList) { if (selectedMemberList) {
@ -235,10 +279,44 @@ const GiveawayModal: FC<OwnProps & StateProps> = ({
openPremiumModal(); openPremiumModal();
}); });
const handleClose = useLastCallback(() => {
setDataStarsPrepaidGiveaway(undefined);
setDataPrepaidGiveaway(undefined);
setSelectedStarOption(undefined);
setSelectedMonthOption(undefined);
setSelectedRandomUserCount(DEFAULT_BOOST_COUNT);
closeGiveawayModal();
});
const handleClick = useLastCallback(() => { const handleClick = useLastCallback(() => {
if (isRandomUsers) { if (isPremiumGiveaway) {
if (selectedUserIds?.length) {
openInvoice({
type: 'giftcode',
boostChannelId: chatId!,
userIds: selectedUserIds,
currency: selectedGift!.currency,
amount: selectedGift!.amount,
option: selectedGift!,
});
} else {
openInvoice({
type: 'giveaway',
chatId: chatId!,
additionalChannelIds: selectedChannelIds,
isOnlyForNewSubscribers: selectedSubscriberOption === 'new',
countries: selectedCountryIds,
areWinnersVisible: shouldShowWinners,
prizeDescription,
untilDate: customExpireDate / 1000,
currency: selectedGift!.currency,
amount: selectedGift!.amount,
option: selectedGift!,
});
}
} else {
openInvoice({ openInvoice({
type: 'giveaway', type: 'starsgiveaway',
chatId: chatId!, chatId: chatId!,
additionalChannelIds: selectedChannelIds, additionalChannelIds: selectedChannelIds,
isOnlyForNewSubscribers: selectedSubscriberOption === 'new', isOnlyForNewSubscribers: selectedSubscriberOption === 'new',
@ -246,47 +324,61 @@ const GiveawayModal: FC<OwnProps & StateProps> = ({
areWinnersVisible: shouldShowWinners, areWinnersVisible: shouldShowWinners,
prizeDescription, prizeDescription,
untilDate: customExpireDate / 1000, untilDate: customExpireDate / 1000,
currency: selectedGift!.currency, currency: selectedStarOption!.currency,
amount: selectedGift!.amount, amount: selectedStarOption!.amount,
option: selectedGift!, stars: selectedStarOption!.stars,
}); users: selectedRandomUserCount,
} else {
openInvoice({
type: 'giftcode',
boostChannelId: chatId!,
userIds: selectedUserIds,
currency: selectedGift!.currency,
amount: selectedGift!.amount,
option: selectedGift!,
}); });
} }
closeGiveawayModal(); handleClose();
}); });
const confirmLaunchPrepaidGiveaway = useLastCallback(() => { const confirmLaunchPrepaidGiveaway = useLastCallback(() => {
launchPrepaidGiveaway({ if (isStarsPrepaidGiveaway) {
chatId: chatId!, launchPrepaidStarsGiveaway({
giveawayId: dataPrepaidGiveaway!.id, chatId: chatId!,
paymentPurpose: { giveawayId: dataStarsPrepaidGiveaway!.id,
additionalChannelIds: selectedChannelIds, paymentPurpose: {
countries: selectedCountryIds, additionalChannelIds: selectedChannelIds,
prizeDescription, countries: selectedCountryIds,
areWinnersVisible: shouldShowWinners, prizeDescription,
untilDate: customExpireDate / 1000, areWinnersVisible: shouldShowWinners,
currency: selectedGift!.currency, untilDate: customExpireDate / 1000,
amount: selectedGift!.amount, stars: dataStarsPrepaidGiveaway!.stars,
}, currency: selectedStarsGift!.currency,
}); amount: selectedStarsGift!.amount,
users: dataStarsPrepaidGiveaway!.quantity,
},
});
} else {
launchPrepaidGiveaway({
chatId: chatId!,
giveawayId: dataPrepaidGiveaway!.id,
paymentPurpose: {
additionalChannelIds: selectedChannelIds,
countries: selectedCountryIds,
prizeDescription,
areWinnersVisible: shouldShowWinners,
untilDate: customExpireDate / 1000,
currency: selectedGift!.currency,
amount: selectedGift!.amount,
},
});
}
closeConfirmModal(); closeConfirmModal();
closeGiveawayModal(); handleClose();
}); });
const handleRandomUserCountChange = useLastCallback((newValue) => { const handleRandomUserCountChange = useLastCallback((newValue) => {
setSelectedRandomUserCount(newValue); setSelectedRandomUserCount(newValue);
}); });
const handleWinnerCountChange = useLastCallback((newValue) => {
setSelectedRandomUserCount(newValue);
});
const handlePrizeDescriptionChange = useLastCallback((e: ChangeEvent<HTMLInputElement>) => { const handlePrizeDescriptionChange = useLastCallback((e: ChangeEvent<HTMLInputElement>) => {
setPrizeDescription(e.target.value); setPrizeDescription(e.target.value);
}); });
@ -309,6 +401,7 @@ const GiveawayModal: FC<OwnProps & StateProps> = ({
const handleChangeTypeOption = useLastCallback((value: ApiGiveawayType) => { const handleChangeTypeOption = useLastCallback((value: ApiGiveawayType) => {
setGiveawayOption(value); setGiveawayOption(value);
setSelectedUserIds([]); setSelectedUserIds([]);
setSelectedRandomUserCount(DEFAULT_BOOST_COUNT);
}); });
const handleExpireDateChange = useLastCallback((date: Date) => { const handleExpireDateChange = useLastCallback((date: Date) => {
@ -323,7 +416,7 @@ const GiveawayModal: FC<OwnProps & StateProps> = ({
const handleSelectedUserIdsChange = useLastCallback((newSelectedIds: string[]) => { const handleSelectedUserIdsChange = useLastCallback((newSelectedIds: string[]) => {
setSelectedUserIds(newSelectedIds); setSelectedUserIds(newSelectedIds);
if (!newSelectedIds.length) { if (!newSelectedIds.length) {
setGiveawayOption('random_users'); setGiveawayOption('premium_giveaway');
} }
}); });
@ -331,10 +424,6 @@ const GiveawayModal: FC<OwnProps & StateProps> = ({
setSelectedChannelIds(newSelectedIds); setSelectedChannelIds(newSelectedIds);
}); });
const handleClose = useLastCallback(() => {
closeGiveawayModal();
});
const handleShouldShowWinnersChange = useLastCallback((e: ChangeEvent<HTMLInputElement>) => { const handleShouldShowWinnersChange = useLastCallback((e: ChangeEvent<HTMLInputElement>) => {
setShouldShowWinners(e.target.checked); setShouldShowWinners(e.target.checked);
}); });
@ -347,7 +436,9 @@ const GiveawayModal: FC<OwnProps & StateProps> = ({
openCountryPickerModal(); openCountryPickerModal();
}); });
if (!gifts) return undefined; const handleStarClick = useLastCallback((option) => {
setSelectedStarOption(option);
});
function renderTypeOptions() { function renderTypeOptions() {
return ( return (
@ -428,12 +519,177 @@ const GiveawayModal: FC<OwnProps & StateProps> = ({
setSelectedChannelIds(filteredChannelIds); setSelectedChannelIds(filteredChannelIds);
} }
function renderStarOptionList() {
return (
<StarTopupOptionList
className={styles.starOptions}
options={starsGiftOptions}
selectedStarCount={selectedRandomUserCount}
selectedStarOption={selectedStarOption}
onClick={handleStarClick}
/>
);
}
function renderGiveawayOptionList() {
return (
<>
<div className={styles.section}>
<h2 className={styles.giveawayTitle}>
{lang('BoostingChannelsGroupsIncludedGiveaway')}
</h2>
<ListItem
inactive
className="chat-item-clickable contact-list-item"
>
<GroupChatInfo
chatId={chatId!}
status={lang(isChannel ? 'BoostingChannelWillReceiveBoost'
: 'BoostingGroupWillReceiveBoost', boostQuantity || boostStarsQuantity, 'i')}
/>
</ListItem>
{selectedChannelIds?.map((channelId) => {
return (
<ListItem
ripple
key={channelId}
className="chat-item-clickable contact-list-item"
/* eslint-disable-next-line react/jsx-no-bind */
onClick={() => deleteParticipantsHandler(channelId)}
rightElement={(<Icon name="close" className={styles.removeChannel} />)}
>
<GroupChatInfo
chatId={channelId.toString()}
/>
</ListItem>
);
})}
{selectedChannelIds.length < MAX_ADDITIONAL_CHANNELS && (
<ListItem
icon="add"
ripple
onClick={openChannelPickerModal}
className={styles.addButton}
iconClassName={styles.addChannel}
>
{lang('BoostingAddChannelOrGroup')}
</ListItem>
)}
</div>
<div className={styles.section}>
<h2 className={styles.giveawayTitle}>
{lang('BoostingEligibleUsers')}
</h2>
{renderSubscribersOptions()}
</div>
<div className={styles.subscription}>
{renderText(lang(isChannel ? 'BoostGift.LimitSubscribersInfo' : 'lng_giveaway_users_about_group'))}
</div>
<div className={styles.section}>
<div className={styles.checkboxSection}>
<h2 className={styles.title}>
{lang('BoostingGiveawayAdditionalPrizes')}
</h2>
<Switcher
label={lang('BoostingGiveawayAdditionalPrizes')}
checked={shouldShowPrizes}
onChange={handleShouldShowPrizesChange}
/>
</div>
{shouldShowPrizes && (
<div className={styles.prizesSection}>
<h2 className={styles.title}>
{selectedRandomUserCount}
</h2>
<InputText
className={styles.prizesInput}
value={prizeDescription}
onChange={handlePrizeDescriptionChange}
label={lang('BoostingGiveawayEnterYourPrize')}
/>
</div>
)}
</div>
{shouldShowPrizes ? (
!isStarsGiveaway && !isStarsPrepaidGiveaway ? (
<div className={styles.subscription}>
{prizeDescription?.length ? renderText(lang('BoostingGiveawayAdditionPrizeCountNameHint',
dataPrepaidGiveaway
? [dataPrepaidGiveaway.quantity, prizeDescription, monthQuantity]
: [selectedUserCount, prizeDescription, monthQuantity],
undefined,
selectedMonthOption), ['simple_markdown']) : renderText(lang('BoostingGiveawayAdditionPrizeCountHint',
dataPrepaidGiveaway
? [dataPrepaidGiveaway.quantity, monthQuantity]
: [selectedUserCount, monthQuantity],
undefined,
selectedMonthOption), ['simple_markdown'])}
</div>
) : undefined
) : (
<div className={styles.subscription}>
{renderText(lang('BoostingGiveawayAdditionPrizeHint'))}
</div>
)}
<div className={styles.section}>
<div className={styles.checkboxSection}>
<h2 className={styles.title}>
{lang('BoostingGiveawayShowWinners')}
</h2>
<Switcher
label={lang('BoostingGiveawayAdditionalPrizes')}
checked={shouldShowWinners}
onChange={handleShouldShowWinnersChange}
/>
</div>
</div>
<div className={styles.subscription}>
{renderText(lang('BoostingGiveawayShowWinnersHint'))}
</div>
<div className={buildClassName(styles.section,
(dataPrepaidGiveaway || dataStarsPrepaidGiveaway || isStarsGiveaway) && styles.subscriptionFooter)}
>
<h2 className={styles.giveawayTitle}>
{lang('BoostingDateWhenGiveawayEnds')}
</h2>
<Button
ariaLabel={lang('BoostGift.DateEnds')}
className={buildClassName(styles.dateButton, 'expire-limit')}
isText
onClick={openCalendar}
>
<h3 className={styles.title}>
{lang('BoostGift.DateEnds')}
</h3>
{formatDateTimeToString(customExpireDate, lang.code)}
</Button>
</div>
</>
);
}
return ( return (
<Modal <Modal
className={styles.root} className={styles.root}
onClose={handleClose} onClose={handleClose}
isOpen={isOpen} isOpen={isOpen}
dialogRef={dialogRef} dialogRef={dialogRef}
onEnter={(dataPrepaidGiveaway || dataStarsPrepaidGiveaway) ? openConfirmModal : handleClick}
> >
<div className={styles.main} onScroll={handleScroll}> <div className={styles.main} onScroll={handleScroll}>
<Button <Button
@ -458,22 +714,31 @@ const GiveawayModal: FC<OwnProps & StateProps> = ({
{lang('BoostingBoostsViaGifts')} {lang('BoostingBoostsViaGifts')}
</h2> </h2>
</div> </div>
{dataPrepaidGiveaway ? ( {(dataPrepaidGiveaway || dataStarsPrepaidGiveaway) ? (
<div className={styles.status}> <div className={styles.status}>
<div> <div>
<img className={styles.prepaidImg} src={GIVEAWAY_IMG_LIST[dataPrepaidGiveaway.months]} alt="" /> {dataStarsPrepaidGiveaway ? (
<img className={styles.prepaidImg} src={GiftStar} alt="" />
) : (
<img className={styles.prepaidImg} src={GIVEAWAY_IMG_LIST[dataPrepaidGiveaway!.months]} alt="" />
)}
</div> </div>
<div className={styles.info}> <div className={styles.info}>
<h3 className={styles.title}> <h3 className={styles.title}>
{lang('BoostingTelegramPremiumCountPlural', dataPrepaidGiveaway.quantity)} {dataStarsPrepaidGiveaway ? lang('Giveaway.Stars.Prepaid.Title', dataStarsPrepaidGiveaway?.stars)
: lang('BoostingTelegramPremiumCountPlural', dataPrepaidGiveaway!.quantity)}
</h3> </h3>
<p className={styles.month}>{lang('PrepaidGiveawayMonths', dataPrepaidGiveaway.months)}</p> <p className={styles.month}>
{dataStarsPrepaidGiveaway ? lang('Giveaway.Stars.Prepaid.Desc', dataStarsPrepaidGiveaway?.quantity)
: lang('PrepaidGiveawayMonths', dataPrepaidGiveaway?.months)}
</p>
</div> </div>
<div className={styles.quantity}> <div className={styles.quantity}>
<div className={buildClassName(styles.floatingBadge, styles.floatingBadgeColor)}> <div className={buildClassName(styles.floatingBadge, styles.floatingBadgeColor)}>
<Icon name="boost" className={styles.floatingBadgeIcon} /> <Icon name="boost" className={styles.floatingBadgeIcon} />
<div className={styles.floatingBadgeValue} dir={lang.isRtl ? 'rtl' : undefined}> <div className={styles.floatingBadgeValue} dir={lang.isRtl ? 'rtl' : undefined}>
{dataPrepaidGiveaway.quantity * (giveawayBoostPerPremiumLimit ?? GIVEAWAY_BOOST_PER_PREMIUM)} {dataStarsPrepaidGiveaway ? dataStarsPrepaidGiveaway?.boosts
: dataPrepaidGiveaway!.quantity * (giveawayBoostPerPremiumLimit ?? GIVEAWAY_BOOST_PER_PREMIUM)}
</div> </div>
</div> </div>
</div> </div>
@ -484,9 +749,9 @@ const GiveawayModal: FC<OwnProps & StateProps> = ({
</div> </div>
)} )}
{isRandomUsers && ( {isPremiumGiveaway && !selectedUserIds?.length && (
<> <>
{!dataPrepaidGiveaway && ( {!dataPrepaidGiveaway && !dataStarsPrepaidGiveaway && (
<> <>
<div className={styles.section}> <div className={styles.section}>
<div className={styles.quantity}> <div className={styles.quantity}>
@ -514,151 +779,57 @@ const GiveawayModal: FC<OwnProps & StateProps> = ({
</> </>
)} )}
<div className={styles.section}> {renderGiveawayOptionList()}
<h2 className={styles.giveawayTitle}>
{lang('BoostingChannelsIncludedGiveaway')}
</h2>
<ListItem
inactive
className="chat-item-clickable contact-list-item"
>
<GroupChatInfo
chatId={chatId!}
status={lang(isChannel ? 'BoostingChannelWillReceiveBoost'
: 'BoostingGroupWillReceiveBoost', boostQuantity, 'i')}
/>
</ListItem>
{selectedChannelIds?.map((channelId) => {
return (
<ListItem
ripple
key={channelId}
className="chat-item-clickable contact-list-item"
/* eslint-disable-next-line react/jsx-no-bind */
onClick={() => deleteParticipantsHandler(channelId)}
rightElement={(<Icon name="close" className={styles.removeChannel} />)}
>
<GroupChatInfo
chatId={channelId.toString()}
/>
</ListItem>
);
})}
{selectedChannelIds.length < MAX_ADDITIONAL_CHANNELS && (
<ListItem
icon="add"
ripple
onClick={openChannelPickerModal}
className={styles.addButton}
iconClassName={styles.addChannel}
>
{lang('BoostingAddChannelOrGroup')}
</ListItem>
)}
</div>
<div className={styles.section}>
<h2 className={styles.giveawayTitle}>
{lang('BoostingEligibleUsers')}
</h2>
{renderSubscribersOptions()}
</div>
<div className={styles.subscription}>
{renderText(lang(isChannel ? 'BoostGift.LimitSubscribersInfo' : 'lng_giveaway_users_about_group'))}
</div>
<div className={styles.section}>
<div className={styles.checkboxSection}>
<h2 className={styles.title}>
{lang('BoostingGiveawayAdditionalPrizes')}
</h2>
<Switcher
label={lang('BoostingGiveawayAdditionalPrizes')}
checked={shouldShowPrizes}
onChange={handleShouldShowPrizesChange}
/>
</div>
{shouldShowPrizes && (
<div className={styles.prizesSection}>
<h2 className={styles.title}>
{dataPrepaidGiveaway ? dataPrepaidGiveaway.quantity : selectedUserCount}
</h2>
<InputText
className={styles.prizesInput}
value={prizeDescription}
onChange={handlePrizeDescriptionChange}
label={lang('BoostingGiveawayEnterYourPrize')}
/>
</div>
)}
</div>
{shouldShowPrizes ? (
<div className={styles.subscription}>
{prizeDescription?.length ? renderText(lang('BoostingGiveawayAdditionPrizeCountNameHint',
dataPrepaidGiveaway
? [dataPrepaidGiveaway.quantity, prizeDescription, monthQuantity]
: [selectedUserCount, prizeDescription, monthQuantity],
undefined,
selectedMonthOption), ['simple_markdown']) : renderText(lang('BoostingGiveawayAdditionPrizeCountHint',
dataPrepaidGiveaway
? [dataPrepaidGiveaway.quantity, monthQuantity]
: [selectedUserCount, monthQuantity],
undefined,
selectedMonthOption), ['simple_markdown'])}
</div>
) : (
<div className={styles.subscription}>
{renderText(lang('BoostingGiveawayAdditionPrizeHint'))}
</div>
)}
<div className={styles.section}>
<div className={styles.checkboxSection}>
<h2 className={styles.title}>
{lang('BoostingGiveawayShowWinners')}
</h2>
<Switcher
label={lang('BoostingGiveawayAdditionalPrizes')}
checked={shouldShowWinners}
onChange={handleShouldShowWinnersChange}
/>
</div>
</div>
<div className={styles.subscription}>
{renderText(lang('BoostingGiveawayShowWinnersHint'))}
</div>
<div className={buildClassName(styles.section, dataPrepaidGiveaway && styles.subscriptionFooter)}>
<h2 className={styles.giveawayTitle}>
{lang('BoostingDateWhenGiveawayEnds')}
</h2>
<Button
ariaLabel={lang('BoostGift.DateEnds')}
className={buildClassName(styles.dateButton, 'expire-limit')}
isText
onClick={openCalendar}
>
<h3 className={styles.title}>
{lang('BoostGift.DateEnds')}
</h3>
{formatDateTimeToString(customExpireDate, lang.code)}
</Button>
</div>
</> </>
)} )}
{!dataPrepaidGiveaway && ( {isStarsGiveaway && (
<>
{!dataStarsPrepaidGiveaway && !dataPrepaidGiveaway && (
<>
<div className={styles.section}>
<div className={styles.quantity}>
<h2 className={styles.giveawayTitle}>
{lang('BoostingStarsOptions')}
</h2>
<div className={buildClassName(styles.floatingBadge, styles.floatingBadgeColor)}>
<Icon name="boost" className={styles.floatingBadgeIcon} />
<div className={styles.floatingBadgeValue} dir={lang.isRtl ? 'rtl' : undefined}>
{boostStarsQuantity}
</div>
</div>
</div>
{renderStarOptionList()}
</div>
<div className={buildClassName(styles.subscription, styles.starSubscription)}>
{renderText(lang('BoostGift.Stars.Info'))}
</div>
<div className={styles.section}>
<h2 className={styles.giveawayTitle}>
{lang('BoostingStarsQuantityPrizes')}
</h2>
<RangeSliderWithMarks
rangeCount={selectedRandomUserCount}
marks={winnerCountOptions}
onChange={handleWinnerCountChange}
/>
<div className={styles.subscription}>
{renderText(lang('BoostingStarsQuantityPrizesInfo'))}
</div>
</div>
</>
)}
{renderGiveawayOptionList()}
</>
)}
{!dataPrepaidGiveaway && !dataStarsPrepaidGiveaway && isPremiumGiveaway && (
<> <>
<div className={styles.section}> <div className={styles.section}>
<h2 className={styles.giveawayTitle}> <h2 className={styles.giveawayTitle}>
@ -676,16 +847,11 @@ const GiveawayModal: FC<OwnProps & StateProps> = ({
{selectedGiveawayOption && ( {selectedGiveawayOption && (
<div className={styles.footer}> <div className={styles.footer}>
<Button className={styles.button} onClick={dataPrepaidGiveaway ? openConfirmModal : handleClick}> <Button
className={styles.button}
onClick={(dataPrepaidGiveaway || dataStarsPrepaidGiveaway) ? openConfirmModal : handleClick}
>
{lang('BoostingStartGiveaway')} {lang('BoostingStartGiveaway')}
<div className={styles.quantity}>
<div className={buildClassName(styles.floatingBadge, styles.floatingBadgeButtonColor)}>
<Icon name="boost" className={styles.floatingBadgeIcon} />
<div className={styles.floatingBadgeValue} dir={lang.isRtl ? 'rtl' : undefined}>
{dataPrepaidGiveaway ? dataPrepaidGiveaway.quantity : boostQuantity}
</div>
</div>
</div>
</Button> </Button>
</div> </div>
)} )}
@ -748,10 +914,12 @@ export default memo(withGlobal<OwnProps>((global): StateProps => {
selectedMemberList: giveawayModal?.selectedMemberIds, selectedMemberList: giveawayModal?.selectedMemberIds,
selectedChannelList: giveawayModal?.selectedChannelIds, selectedChannelList: giveawayModal?.selectedChannelIds,
giveawayBoostPerPremiumLimit: global.appConfig?.giveawayBoostsPerPremium, giveawayBoostPerPremiumLimit: global.appConfig?.giveawayBoostsPerPremium,
isStarsGiftsEnabled: global.appConfig?.isStarsGiftsEnabled,
userSelectionLimit: global.appConfig?.giveawayAddPeersMax, userSelectionLimit: global.appConfig?.giveawayAddPeersMax,
countrySelectionLimit: global.appConfig?.giveawayCountriesMax, countrySelectionLimit: global.appConfig?.giveawayCountriesMax,
countryList: global.countryList.general, countryList: global.countryList.general,
prepaidGiveaway: giveawayModal?.prepaidGiveaway, prepaidGiveaway: giveawayModal?.prepaidGiveaway,
isChannel, isChannel,
starsGiftOptions: giveawayModal?.starOptions,
}; };
})(GiveawayModal)); })(GiveawayModal));

View File

@ -1,7 +1,7 @@
.wrapper { .wrapper {
position: relative; position: relative;
display: block; display: block;
padding-inline: 3.8125rem 1rem; padding-inline: 3.5rem 1rem;
border: none; border: none;
margin-bottom: 0; margin-bottom: 0;

View File

@ -11,7 +11,7 @@ import Icon from '../../common/icons/Icon';
import styles from './GiveawayTypeOption.module.scss'; import styles from './GiveawayTypeOption.module.scss';
type ApiGiveawayType = 'random_users' | 'specific_users'; type ApiGiveawayType = 'premium_giveaway' | 'stars_giveaway';
type OwnProps = { type OwnProps = {
option: ApiGiveawayType; option: ApiGiveawayType;
@ -54,7 +54,6 @@ const GiveawayTypeOption: FC<OwnProps> = ({
<label <label
className={buildClassName(styles.wrapper, className)} className={buildClassName(styles.wrapper, className)}
dir={lang.isRtl ? 'rtl' : undefined} dir={lang.isRtl ? 'rtl' : undefined}
onClick={handleClick}
role="button" role="button"
tabIndex={0} tabIndex={0}
> >
@ -74,7 +73,7 @@ const GiveawayTypeOption: FC<OwnProps> = ({
{lang(`${name}`)} {lang(`${name}`)}
</h3> </h3>
{isLink ? ( {isLink ? (
<div className={styles.link}> <div className={styles.link} onClick={handleClick}>
<span>{displayText}</span> <span>{displayText}</span>
<Icon name="next" /> <Icon name="next" />
</div> </div>

View File

@ -15,7 +15,6 @@
} }
.root :global(.modal-dialog) { .root :global(.modal-dialog) {
height: min(calc(55vh + 41px + 193px), 90vh);
max-width: 26.25rem; max-width: 26.25rem;
} }
@ -119,5 +118,5 @@
} }
.footer { .footer {
margin: 0 1.5rem; margin: 0 1.5rem 1rem;
} }

View File

@ -15,7 +15,7 @@
.giveawayWrapper { .giveawayWrapper {
position: relative; position: relative;
display: block; display: block;
padding-inline: 3.8125rem 1rem; padding-inline: 3.5rem 1rem;
cursor: var(--custom-cursor, pointer); cursor: var(--custom-cursor, pointer);

View File

@ -4,10 +4,6 @@
} }
} }
.root {
z-index: calc(var(--z-modal-low-priority) + 1);
}
.root :global(.modal-content) { .root :global(.modal-content) {
padding: 0; padding: 0;
} }
@ -15,11 +11,6 @@
.root :global(.modal-dialog) { .root :global(.modal-dialog) {
height: min(calc(55vh + 41px + 193px), 90vh); height: min(calc(55vh + 41px + 193px), 90vh);
max-width: 26.25rem; max-width: 26.25rem;
}
.root :global(.modal-dialog),
.root :global(.modal-content),
.transition {
overflow: hidden; overflow: hidden;
} }
@ -28,6 +19,7 @@
overflow-y: scroll; overflow-y: scroll;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center;
} }
.headerInfo { .headerInfo {

View File

@ -116,6 +116,10 @@ const StarsGiftModal: FC<OwnProps & StateProps> = ({
setHeaderHidden(scrollTop <= 150); setHeaderHidden(scrollTop <= 150);
} }
const handleClose = useLastCallback(() => {
closeStarsGiftModal();
});
function renderGiftTitle() { function renderGiftTitle() {
if (isCompleted) { if (isCompleted) {
return user ? renderText(oldLang('Notification.StarsGift.SentYou', return user ? renderText(oldLang('Notification.StarsGift.SentYou',
@ -149,12 +153,12 @@ const StarsGiftModal: FC<OwnProps & StateProps> = ({
return ( return (
<Modal <Modal
dialogRef={dialogRef}
onClose={closeStarsGiftModal}
isOpen={isOpen}
className={buildClassName(styles.modalDialog, styles.root)} className={buildClassName(styles.modalDialog, styles.root)}
dialogRef={dialogRef}
onClose={handleClose}
isOpen={isOpen}
> >
<div className={buildClassName(styles.main, 'custom-scroll')} onScroll={handleScroll}> <div className={styles.main} onScroll={handleScroll}>
<Button <Button
round round
size="smaller" size="smaller"

View File

@ -35,6 +35,7 @@ import useContextMenuHandlers from '../../hooks/useContextMenuHandlers';
import useEnsureMessage from '../../hooks/useEnsureMessage'; import useEnsureMessage from '../../hooks/useEnsureMessage';
import useFlag from '../../hooks/useFlag'; import useFlag from '../../hooks/useFlag';
import { useIsIntersecting, useOnIntersect } from '../../hooks/useIntersectionObserver'; import { useIsIntersecting, useOnIntersect } from '../../hooks/useIntersectionObserver';
import useLang from '../../hooks/useLang';
import useOldLang from '../../hooks/useOldLang'; import useOldLang from '../../hooks/useOldLang';
import useShowTransitionDeprecated from '../../hooks/useShowTransitionDeprecated'; import useShowTransitionDeprecated from '../../hooks/useShowTransitionDeprecated';
import useFocusMessage from './message/hooks/useFocusMessage'; import useFocusMessage from './message/hooks/useFocusMessage';
@ -105,10 +106,16 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
onIntersectPinnedMessage, onIntersectPinnedMessage,
}) => { }) => {
const { const {
openPremiumModal, requestConfetti, checkGiftCode, getReceipt, openStarsTransactionFromGift, openPremiumModal,
requestConfetti,
checkGiftCode,
getReceipt,
openStarsTransactionFromGift,
openPrizeStarsTransactionFromGiveaway,
} = getActions(); } = getActions();
const oldLang = useOldLang(); const oldLang = useOldLang();
const lang = useLang();
// eslint-disable-next-line no-null/no-null // eslint-disable-next-line no-null/no-null
const ref = useRef<HTMLDivElement>(null); const ref = useRef<HTMLDivElement>(null);
@ -134,6 +141,7 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
const isSuggestedAvatar = message.content.action?.type === 'suggestProfilePhoto' && message.content.action!.photo; const isSuggestedAvatar = message.content.action?.type === 'suggestProfilePhoto' && message.content.action!.photo;
const isJoinedMessage = isJoinedChannelMessage(message); const isJoinedMessage = isJoinedChannelMessage(message);
const isStarsGift = message.content.action?.type === 'giftStars'; const isStarsGift = message.content.action?.type === 'giftStars';
const isPrizeStars = message.content.action?.type === 'prizeStars';
useEffect(() => { useEffect(() => {
if (noAppearanceAnimation) { if (noAppearanceAnimation) {
@ -214,6 +222,13 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
}); });
}; };
const handlePrizeStarsClick = () => {
openPrizeStarsTransactionFromGiveaway({
chatId: message.chatId,
messageId: message.id,
});
};
const handleGiftCodeClick = () => { const handleGiftCodeClick = () => {
const slug = message.content.action?.slug; const slug = message.content.action?.slug;
if (!slug) return; if (!slug) return;
@ -343,6 +358,50 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
); );
} }
function renderPrizeStars() {
const isUnclaimed = message.content.action?.isUnclaimed;
return (
<span
className="action-message-gift action-message-gift-code"
tabIndex={0}
role="button"
onClick={handlePrizeStarsClick}
>
<AnimatedIconFromSticker
key={message.id}
sticker={starGiftSticker}
play={canPlayAnimatedEmojis}
noLoop
nonInteractive
/>
<strong>
{oldLang(isUnclaimed ? 'BoostingUnclaimedPrize' : 'BoostingCongratulations')}
</strong>
<span className="action-message-subtitle">
{targetChat && renderText(oldLang(isUnclaimed
? 'BoostingReceivedPrizeFrom' : 'BoostingYouHaveUnclaimedPrize', getChatTitle(oldLang, targetChat)),
['simple_markdown'])}
</span>
<span className="action-message-subtitle">
{renderText(lang(
'PrizeCredits', {
count: (
<b>{formatInteger(message.content.action?.stars!)}</b>
),
}, {
withNodes: true,
},
), ['simple_markdown'])}
</span>
<span className="action-message-button">{
oldLang('ActionGiftPremiumView')
}
</span>
</span>
);
}
const className = buildClassName( const className = buildClassName(
'ActionMessage message-list-item', 'ActionMessage message-list-item',
isFocused && !noFocusHighlight && 'focused', isFocused && !noFocusHighlight && 'focused',
@ -368,6 +427,7 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
{isPremiumGift && renderGift()} {isPremiumGift && renderGift()}
{isGiftCode && renderGiftCode()} {isGiftCode && renderGiftCode()}
{isStarsGift && renderStarsGift()} {isStarsGift && renderStarsGift()}
{isPrizeStars && renderPrizeStars()}
{isSuggestedAvatar && ( {isSuggestedAvatar && (
<ActionMessageSuggestedAvatar message={message} renderContent={renderContent} /> <ActionMessageSuggestedAvatar message={message} renderContent={renderContent} />
)} )}

View File

@ -68,7 +68,7 @@ const Giveaway = ({
const { giveaway, giveawayResults } = message.content; const { giveaway, giveawayResults } = message.content;
const isResults = Boolean(giveawayResults); const isResults = Boolean(giveawayResults);
const { const {
months, untilDate, prizeDescription, months, untilDate, prizeDescription, stars,
} = (giveaway || giveawayResults)!; } = (giveaway || giveawayResults)!;
const isOwn = isOwnMessage(message); const isOwn = isOwnMessage(message);
@ -130,12 +130,25 @@ const Giveaway = ({
</> </>
)} )}
<p className={styles.description}> <p className={styles.description}>
{renderText(lang('Chat.Giveaway.Info.Subscriptions', quantity), ['simple_markdown'])} {message?.content?.giveaway?.stars ? (
<br /> <>
{renderText(lang( {renderText(
'ActionGiftPremiumSubtitle', lang('Chat.Giveaway.Message.Stars.PrizeText', lang('Stars', message?.content?.giveaway?.stars)),
lang('Chat.Giveaway.Info.Months', months), ['simple_markdown'],
), ['simple_markdown'])} )}
<br />
{renderText(lang('AmongWinners', quantity), ['simple_markdown'])}
</>
) : (
<>
{renderText(lang('Chat.Giveaway.Info.Subscriptions', quantity), ['simple_markdown'])}
<br />
{renderText(lang(
'ActionGiftPremiumSubtitle',
lang('Chat.Giveaway.Info.Months', months),
), ['simple_markdown'])}
</>
)}
</p> </p>
</div> </div>
<div className={styles.section}> <div className={styles.section}>
@ -216,14 +229,14 @@ const Giveaway = ({
const isResultsInfo = giveawayInfo.type === 'results'; const isResultsInfo = giveawayInfo.type === 'results';
const chatTitle = isApiPeerChat(sender) ? getChatTitle(lang, sender) : getUserFullName(sender); const chatTitle = isApiPeerChat(sender) ? getChatTitle(lang, sender) : getUserFullName(sender);
const duration = lang('Chat.Giveaway.Info.Months', months);
const endDate = formatDateAtTime(lang, untilDate * 1000); const endDate = formatDateAtTime(lang, untilDate * 1000);
const otherChannelsCount = giveaway?.channelIds ? giveaway.channelIds.length - 1 : 0; const otherChannelsCount = giveaway?.channelIds ? giveaway.channelIds.length - 1 : 0;
const otherChannelsString = lang('Chat.Giveaway.Info.OtherChannels', otherChannelsCount); const otherChannelsString = lang('Chat.Giveaway.Info.OtherChannels', otherChannelsCount);
const isSeveral = otherChannelsCount > 0; const isSeveral = otherChannelsCount > 0;
const firstKey = isResultsInfo ? 'BoostingGiveawayHowItWorksTextEnd' : 'BoostingGiveawayHowItWorksText'; const firstKey = isResultsInfo ? 'BoostingGiveawayHowItWorksTextEnd' : 'BoostingGiveawayHowItWorksText';
const firstParagraph = lang(firstKey, [chatTitle, quantity, duration], undefined, quantity); const giveawayDuration = isResultsInfo ? lang('Chat.Giveaway.Info.Months', months) : lang('Stars', stars, 'i');
const firstParagraph = lang(firstKey, [chatTitle, quantity, giveawayDuration], undefined, quantity);
const additionalPrizes = prizeDescription const additionalPrizes = prizeDescription
? lang('BoostingGiveawayHowItWorksIncludeText', [chatTitle, quantity, prizeDescription], undefined, quantity) ? lang('BoostingGiveawayHowItWorksIncludeText', [chatTitle, quantity, prizeDescription], undefined, quantity)

View File

@ -731,6 +731,10 @@
width: 1px; width: 1px;
visibility: hidden; visibility: hidden;
} }
.giveaway-result-content {
min-width: 17rem;
}
} }
// Border-radius styles // Border-radius styles

View File

@ -1576,7 +1576,9 @@ const Message: FC<OwnProps & StateProps> = ({
)} )}
{withAvatar && renderAvatar()} {withAvatar && renderAvatar()}
<div <div
className={buildClassName('message-content-wrapper', contentClassName.includes('text') && 'can-select-text')} className={buildClassName('message-content-wrapper',
contentClassName.includes('text') && 'giveaway-result-content',
contentClassName.includes('giveaway') && 'can-select-text')}
> >
<div <div
className={contentClassName} className={contentClassName}

View File

@ -16,11 +16,29 @@
word-break: break-word; word-break: break-word;
} }
.table .cell { .table {
border: 1px solid var(--color-borders); border-collapse: separate;
border-spacing: 0;
}
.cell {
border: solid 0.0625rem var(--color-borders);
border-style: none solid solid none;
padding: 0.25rem 0.5rem; padding: 0.25rem 0.5rem;
} }
.row:first-child .cell:first-child { border-top-left-radius: 0.3125rem; }
.row:first-child .cell:last-child { border-top-right-radius: 0.3125rem; }
.row:last-child .cell:first-child { border-bottom-left-radius: 0.3125rem; }
.row:last-child .cell:last-child { border-bottom-right-radius: 0.3125rem; }
.row:first-child .cell { border-top-style: solid; }
.row .cell:first-child { border-left-style: solid; }
.section { .section {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@ -31,6 +31,7 @@ type OwnProps = {
headerAvatarWebPhoto?: ApiWebDocument; headerAvatarWebPhoto?: ApiWebDocument;
noHeaderImage?: boolean; noHeaderImage?: boolean;
isGift?: boolean; isGift?: boolean;
isPrizeStars?: boolean;
header?: TeactNode; header?: TeactNode;
footer?: TeactNode; footer?: TeactNode;
buttonText?: string; buttonText?: string;
@ -49,6 +50,7 @@ const TableInfoModal = ({
headerAvatarWebPhoto, headerAvatarWebPhoto,
noHeaderImage, noHeaderImage,
isGift, isGift,
isPrizeStars,
header, header,
footer, footer,
buttonText, buttonText,
@ -75,7 +77,7 @@ const TableInfoModal = ({
contentClassName={styles.content} contentClassName={styles.content}
onClose={onClose} onClose={onClose}
> >
{!isGift && !noHeaderImage && ( {!isGift && !isPrizeStars && !noHeaderImage && (
withAvatar ? ( withAvatar ? (
<Avatar peer={headerAvatarPeer} webPhoto={headerAvatarWebPhoto} size="jumbo" className={styles.avatar} /> <Avatar peer={headerAvatarPeer} webPhoto={headerAvatarWebPhoto} size="jumbo" className={styles.avatar} />
) : ( ) : (

View File

@ -28,6 +28,10 @@
} }
} }
.active {
--_background-color: var(--color-background-secondary-accent);
}
.wideOption { .wideOption {
grid-column: 1 / -1; grid-column: 1 / -1;
} }

View File

@ -1,13 +1,17 @@
import type { FC } from '../../../lib/teact/teact'; import type { FC } from '../../../lib/teact/teact';
import React, { memo, useEffect, useMemo } from '../../../lib/teact/teact'; import React, {
memo, useEffect, useMemo,
} from '../../../lib/teact/teact';
import type { ApiStarTopupOption } from '../../../api/types'; import type { ApiStarGiveawayOption, ApiStarTopupOption } from '../../../api/types';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import { formatCurrency } from '../../../util/formatCurrency'; import { formatCurrency } from '../../../util/formatCurrency';
import { formatInteger } from '../../../util/textFormat'; import { formatInteger } from '../../../util/textFormat';
import renderText from '../../common/helpers/renderText';
import useFlag from '../../../hooks/useFlag'; import useFlag from '../../../hooks/useFlag';
import useLang from '../../../hooks/useLang';
import useOldLang from '../../../hooks/useOldLang'; import useOldLang from '../../../hooks/useOldLang';
import Icon from '../../common/icons/Icon'; import Icon from '../../common/icons/Icon';
@ -20,18 +24,25 @@ const MAX_STARS_COUNT = 6;
type OwnProps = { type OwnProps = {
isActive?: boolean; isActive?: boolean;
options?: ApiStarTopupOption[]; options?: ApiStarTopupOption[] | ApiStarGiveawayOption[];
selectedStarOption?: ApiStarTopupOption | ApiStarGiveawayOption;
selectedStarCount?: number;
starsNeeded?: number; starsNeeded?: number;
onClick: (option: ApiStarTopupOption) => void; className?: string;
onClick: (option: ApiStarTopupOption | ApiStarGiveawayOption) => void;
}; };
const StarTopupOptionList: FC<OwnProps> = ({ const StarTopupOptionList: FC<OwnProps> = ({
isActive, isActive,
className,
options, options,
selectedStarOption,
selectedStarCount,
starsNeeded, starsNeeded,
onClick, onClick,
}) => { }) => {
const lang = useOldLang(); const oldLang = useOldLang();
const lang = useLang();
const [areOptionsExtended, markOptionsExtended, unmarkOptionsExtended] = useFlag(); const [areOptionsExtended, markOptionsExtended, unmarkOptionsExtended] = useFlag();
@ -51,7 +62,7 @@ const StarTopupOptionList: FC<OwnProps> = ({
)); ));
const forceShowAll = starsNeeded && maxOption.stars < starsNeeded; const forceShowAll = starsNeeded && maxOption.stars < starsNeeded;
const result: { option: ApiStarTopupOption; starsCount: number; isWide: boolean }[] = []; const result: { option: ApiStarTopupOption | ApiStarGiveawayOption; starsCount: number; isWide: boolean }[] = [];
let currentStackedStarsCount = 0; let currentStackedStarsCount = 0;
let canExtendOptions = false; let canExtendOptions = false;
options.forEach((option, index) => { options.forEach((option, index) => {
@ -73,13 +84,24 @@ const StarTopupOptionList: FC<OwnProps> = ({
}, [areOptionsExtended, options, starsNeeded]); }, [areOptionsExtended, options, starsNeeded]);
return ( return (
<div className={styles.options}> <div className={buildClassName(styles.options, className)}>
{renderingOptions?.map(({ option, starsCount, isWide }) => { {renderingOptions?.map(({ option, starsCount, isWide }) => {
const length = renderingOptions?.length; const length = renderingOptions?.length;
const isOdd = length % 2 === 0; const isOdd = length % 2 === 0;
const isActiveOption = option === selectedStarOption;
let perUserStarCount;
if (option && 'winners' in option) {
const winner = option.winners.find((opt) => opt.users === selectedStarCount)
|| option.winners.reduce((max, opt) => (opt.users > max.users ? opt : max), option.winners[0]);
perUserStarCount = winner?.perUserStars;
}
return ( return (
<div <div
className={buildClassName(styles.option, (!isOdd && isWide) && styles.wideOption)} className={buildClassName(
styles.option, (!isOdd && isWide) && styles.wideOption, isActiveOption && styles.active,
)}
key={option.stars} key={option.stars}
onClick={() => onClick?.(option)} onClick={() => onClick?.(option)}
> >
@ -92,14 +114,21 @@ const StarTopupOptionList: FC<OwnProps> = ({
</div> </div>
</div> </div>
<div className={styles.optionBottom}> <div className={styles.optionBottom}>
{formatCurrency(option.amount, option.currency, lang.code)} {formatCurrency(option.amount, option.currency, oldLang.code)}
</div> </div>
{(isActiveOption || (selectedStarOption && 'winners' in selectedStarOption)) && perUserStarCount && (
<div className={styles.optionBottom}>
<div className={styles.perUserStars}>
{renderText(oldLang('BoostGift.Stars.PerUser', formatInteger(perUserStarCount)))}
</div>
</div>
)}
</div> </div>
); );
})} })}
{!areOptionsExtended && canExtend && ( {!areOptionsExtended && canExtend && (
<Button className={styles.moreOptions} isText noForcedUpperCase onClick={markOptionsExtended}> <Button className={styles.moreOptions} isText noForcedUpperCase onClick={markOptionsExtended}>
{lang('Stars.Purchase.ShowMore')} {oldLang('Stars.Purchase.ShowMore')}
<Icon className={styles.iconDown} name="down" /> <Icon className={styles.iconDown} name="down" />
</Button> </Button>
)} )}

View File

@ -56,6 +56,7 @@ const StarsTransactionModal: FC<OwnProps & StateProps> = ({
const lang = useLang(); const lang = useLang();
const { transaction } = modal || {}; const { transaction } = modal || {};
const isGift = transaction?.isGift; const isGift = transaction?.isGift;
const isPrizeStars = transaction?.isPrizeStars;
const handleOpenMedia = useLastCallback(() => { const handleOpenMedia = useLastCallback(() => {
const media = transaction?.extendedMedia; const media = transaction?.extendedMedia;
@ -158,7 +159,7 @@ const StarsTransactionModal: FC<OwnProps & StateProps> = ({
onClick={handleOpenMedia} onClick={handleOpenMedia}
/> />
)} )}
{isGift ? animatedStickerData : ( {(isGift || isPrizeStars) ? animatedStickerData : (
<img <img
className={buildClassName(styles.starsBackground, media && styles.mediaShift)} className={buildClassName(styles.starsBackground, media && styles.mediaShift)}
src={StarsBackground} src={StarsBackground}
@ -167,9 +168,10 @@ const StarsTransactionModal: FC<OwnProps & StateProps> = ({
/> />
)} )}
{title && <h1 className={styles.title}>{title}</h1>} {title && <h1 className={styles.title}>{title}</h1>}
{isGift && ( {(isGift || isPrizeStars) && (
<h1 className={buildClassName(styles.title, styles.starTitle)}> <h1 className={buildClassName(styles.title, styles.starTitle)}>
{transaction?.isMyGift ? oldLang('StarsGiftSent') : oldLang('StarsGiftReceived')} {isPrizeStars ? oldLang('StarsGiveawayPrizeReceived')
: transaction?.isMyGift ? oldLang('StarsGiftSent') : oldLang('StarsGiftReceived')}
</h1> </h1>
)} )}
<p className={styles.description}>{description}</p> <p className={styles.description}>{description}</p>
@ -199,7 +201,14 @@ const StarsTransactionModal: FC<OwnProps & StateProps> = ({
tableData.push([oldLang('Stars.Transaction.Media'), <SafeLink url={messageLink} text={messageLink} />]); tableData.push([oldLang('Stars.Transaction.Media'), <SafeLink url={messageLink} text={messageLink} />]);
} }
if (transaction.id) { if (isPrizeStars) {
tableData.push(
[oldLang('BoostReason'), oldLang('Giveaway')],
[oldLang('Gift'), oldLang('Stars', transaction.stars, 'i')],
);
}
if (transaction.id && !isPrizeStars) {
tableData.push([ tableData.push([
oldLang('Stars.Transaction.Id'), oldLang('Stars.Transaction.Id'),
( (
@ -241,7 +250,9 @@ const StarsTransactionModal: FC<OwnProps & StateProps> = ({
footer, footer,
avatarPeer: !transaction.photo ? (peer || customPeer) : undefined, avatarPeer: !transaction.photo ? (peer || customPeer) : undefined,
}; };
}, [transaction, oldLang, peer, isGift, animatedStickerData, giftOutAboutText, giftEntryAboutText]); }, [
transaction, oldLang, peer, isGift, isPrizeStars, animatedStickerData, giftOutAboutText, giftEntryAboutText,
]);
const prevModalData = usePreviousDeprecated(starModalData); const prevModalData = usePreviousDeprecated(starModalData);
const renderingModalData = prevModalData || starModalData; const renderingModalData = prevModalData || starModalData;
@ -252,6 +263,7 @@ const StarsTransactionModal: FC<OwnProps & StateProps> = ({
className={styles.modal} className={styles.modal}
header={renderingModalData?.header} header={renderingModalData?.header}
isGift={isGift} isGift={isGift}
isPrizeStars={isPrizeStars}
tableData={renderingModalData?.tableData} tableData={renderingModalData?.tableData}
footer={renderingModalData?.footer} footer={renderingModalData?.footer}
noHeaderImage={Boolean(transaction?.extendedMedia)} noHeaderImage={Boolean(transaction?.extendedMedia)}

View File

@ -3,7 +3,7 @@ import React, {
} from '../../../lib/teact/teact'; } from '../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../global'; import { getActions, withGlobal } from '../../../global';
import type { ApiBoost, ApiBoostStatistics, ApiPrepaidGiveaway } from '../../../api/types'; import type { ApiBoost, ApiBoostStatistics, ApiTypePrepaidGiveaway } from '../../../api/types';
import type { TabState } from '../../../global/types'; import type { TabState } from '../../../global/types';
import { import {
@ -17,7 +17,7 @@ import {
} from '../../../global/selectors'; } from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import { formatDateAtTime } from '../../../util/dates/dateFormat'; import { formatDateAtTime } from '../../../util/dates/dateFormat';
import { CUSTOM_PEER_TO_BE_DISTRIBUTED } from '../../../util/objects/customPeer'; import { CUSTOM_PEER_STAR, CUSTOM_PEER_TO_BE_DISTRIBUTED } from '../../../util/objects/customPeer';
import { formatInteger } from '../../../util/textFormat'; import { formatInteger } from '../../../util/textFormat';
import { getBoostProgressInfo } from '../../common/helpers/boostInfo'; import { getBoostProgressInfo } from '../../common/helpers/boostInfo';
@ -40,6 +40,7 @@ import styles from './BoostStatistics.module.scss';
import GiftBlueRound from '../../../assets/premium/GiftBlueRound.svg'; import GiftBlueRound from '../../../assets/premium/GiftBlueRound.svg';
import GiftGreenRound from '../../../assets/premium/GiftGreenRound.svg'; import GiftGreenRound from '../../../assets/premium/GiftGreenRound.svg';
import GiftRedRound from '../../../assets/premium/GiftRedRound.svg'; import GiftRedRound from '../../../assets/premium/GiftRedRound.svg';
import GiftStar from '../../../assets/premium/GiftStar.svg';
type StateProps = { type StateProps = {
boostStatistics: TabState['boostStatistics']; boostStatistics: TabState['boostStatistics'];
@ -196,6 +197,8 @@ const BoostStatistics = ({
}); });
const renderBoostList = useLastCallback((boost) => { const renderBoostList = useLastCallback((boost) => {
const hasStars = Boolean(boost?.stars);
return ( return (
<ListItem <ListItem
className="chat-item-clickable" className="chat-item-clickable"
@ -205,7 +208,8 @@ const BoostStatistics = ({
<PrivateChatInfo <PrivateChatInfo
className={styles.user} className={styles.user}
userId={boost.userId} userId={boost.userId}
customPeer={!boost.userId ? CUSTOM_PEER_TO_BE_DISTRIBUTED : undefined} customPeer={hasStars ? { ...CUSTOM_PEER_STAR, titleValue: boost.stars }
: (!boost.userId ? CUSTOM_PEER_TO_BE_DISTRIBUTED : undefined)}
status={lang('BoostExpireOn', formatDateAtTime(lang, boost.expires * 1000))} status={lang('BoostExpireOn', formatDateAtTime(lang, boost.expires * 1000))}
noEmojiStatus noEmojiStatus
forceShowSelf forceShowSelf
@ -218,8 +222,7 @@ const BoostStatistics = ({
); );
}); });
const handleGiveawayClick = useLastCallback((e) => { const handleGiveawayClick = useLastCallback(() => {
e.preventDefault();
openGiveawayModal({ chatId }); openGiveawayModal({ chatId });
}); });
@ -228,7 +231,7 @@ const BoostStatistics = ({
loadMoreBoosters({ isGifts: tabType === 'giftedBoostList' }); loadMoreBoosters({ isGifts: tabType === 'giftedBoostList' });
}); });
const launchPrepaidGiveawayHandler = useLastCallback((prepaidGiveaway: ApiPrepaidGiveaway) => { const launchPrepaidGiveawayHandler = useLastCallback((prepaidGiveaway: ApiTypePrepaidGiveaway) => {
openGiveawayModal({ chatId, prepaidGiveaway }); openGiveawayModal({ chatId, prepaidGiveaway });
}); });
@ -271,45 +274,65 @@ const BoostStatistics = ({
<h4 className={styles.sectionHeader} dir={lang.isRtl ? 'rtl' : undefined}> <h4 className={styles.sectionHeader} dir={lang.isRtl ? 'rtl' : undefined}>
{lang('BoostingPreparedGiveaways')} {lang('BoostingPreparedGiveaways')}
</h4> </h4>
{statsOverview?.prepaidGiveaways?.map((prepaidGiveaway) => ( {statsOverview?.prepaidGiveaways?.map((prepaidGiveaway) => {
<ListItem const isStarsGiveaway = 'stars' in prepaidGiveaway;
key={prepaidGiveaway.id}
className="chat-item-clickable" return (
// eslint-disable-next-line react/jsx-no-bind <ListItem
onClick={() => launchPrepaidGiveawayHandler(prepaidGiveaway)} key={prepaidGiveaway.id}
> className="chat-item-clickable"
<div className={buildClassName(styles.status, 'status-clickable')}> // eslint-disable-next-line react/jsx-no-bind
<div> onClick={() => launchPrepaidGiveawayHandler(prepaidGiveaway)}
<img >
src={GIVEAWAY_IMG_LIST[prepaidGiveaway.months]} <div className={buildClassName(styles.status, 'status-clickable')}>
className={styles.giveawayIcon} <div>
alt={lang('Giveaway')} {isStarsGiveaway
/> ? (
</div> <img
<div className={styles.info}> src={GiftStar}
<h3> className={styles.giveawayIcon}
{lang('BoostingTelegramPremiumCountPlural', prepaidGiveaway.quantity)} alt={lang('GiftStar')}
</h3> />
<p className={styles.month}>{lang('PrepaidGiveawayMonths', prepaidGiveaway.months)}</p> ) : (
</div> <img
<div className={styles.quantity}> src={GIVEAWAY_IMG_LIST[prepaidGiveaway.months]}
<div className={buildClassName(styles.floatingBadge, className={styles.giveawayIcon}
styles.floatingBadgeButtonColor, alt={lang('Giveaway')}
styles.floatingBadgeButton)} />
> )}
<Icon name="boost" className={styles.floatingBadgeIcon} /> </div>
<div className={styles.floatingBadgeValue} dir={lang.isRtl ? 'rtl' : undefined}> <div className={styles.info}>
{prepaidGiveaway.quantity * (giveawayBoostsPerPremium ?? GIVEAWAY_BOOST_PER_PREMIUM)} <h3>
{isStarsGiveaway
? lang('Giveaway.Stars.Prepaid.Title', prepaidGiveaway.stars)
: lang('BoostingTelegramPremiumCountPlural', prepaidGiveaway.quantity)}
</h3>
<p className={styles.month}>{
isStarsGiveaway ? lang('Giveaway.Stars.Prepaid.Desc', prepaidGiveaway.quantity)
: lang('PrepaidGiveawayMonths', prepaidGiveaway.months)
}
</p>
</div>
<div className={styles.quantity}>
<div className={buildClassName(styles.floatingBadge,
styles.floatingBadgeButtonColor,
styles.floatingBadgeButton)}
>
<Icon name="boost" className={styles.floatingBadgeIcon} />
<div className={styles.floatingBadgeValue} dir={lang.isRtl ? 'rtl' : undefined}>
{isStarsGiveaway ? prepaidGiveaway.boosts
: prepaidGiveaway.quantity * (giveawayBoostsPerPremium ?? GIVEAWAY_BOOST_PER_PREMIUM)}
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </ListItem>
</ListItem> );
))} })}
<p className="text-muted hint" key="links-hint">{lang('BoostingSelectPaidGiveaway')}</p> <p className="text-muted hint" key="links-hint">{lang('BoostingSelectPaidGiveaway')}</p>
</div> </div>
)} )}
<div> <div className={styles.section}>
{shouldDisplayGiftList ? ( {shouldDisplayGiftList ? (
<div <div
className={buildClassName(styles.boostSection, styles.content)} className={buildClassName(styles.boostSection, styles.content)}
@ -326,7 +349,7 @@ const BoostStatistics = ({
<TabList activeTab={renderingActiveTab} tabs={tabs} onSwitchTab={setActiveTab} /> <TabList activeTab={renderingActiveTab} tabs={tabs} onSwitchTab={setActiveTab} />
</div> </div>
) : ( ) : (
<div className={styles.section}> <>
<h4 className={styles.sectionHeader} dir={lang.isRtl ? 'rtl' : undefined}> <h4 className={styles.sectionHeader} dir={lang.isRtl ? 'rtl' : undefined}>
{lang('BoostingBoostsCount', boostStatistics?.boosts?.count)} {lang('BoostingBoostsCount', boostStatistics?.boosts?.count)}
</h4> </h4>
@ -335,25 +358,23 @@ const BoostStatistics = ({
</div> </div>
)} )}
{boostStatistics?.boosts?.list?.map((boost) => renderBoostList(boost))} {boostStatistics?.boosts?.list?.map((boost) => renderBoostList(boost))}
</div> </>
)}
{Boolean(boostersToLoadCount) && (
<ListItem
key="load-more"
className={styles.showMore}
disabled={boostStatistics?.isLoadingBoosters}
onClick={handleLoadMore}
>
{boostStatistics?.isLoadingBoosters ? (
<Spinner className={styles.loadMoreSpinner} />
) : (
<Icon name="down" className={styles.down} />
)}
{lang('ShowVotes', boostersToLoadCount, 'i')}
</ListItem>
)} )}
<div className={styles.section}>
{Boolean(boostersToLoadCount) && (
<ListItem
key="load-more"
className={styles.showMore}
disabled={boostStatistics?.isLoadingBoosters}
onClick={handleLoadMore}
>
{boostStatistics?.isLoadingBoosters ? (
<Spinner className={styles.loadMoreSpinner} />
) : (
<Icon name="down" className={styles.down} />
)}
{lang('ShowVotes', boostersToLoadCount, 'i')}
</ListItem>
)}
</div>
</div> </div>
<LinkField className={styles.section} link={status!.boostUrl} withShare title={lang('LinkForBoosting')} /> <LinkField className={styles.section} link={status!.boostUrl} withShare title={lang('LinkForBoosting')} />
{isGiveawayAvailable && ( {isGiveawayAvailable && (

View File

@ -7,14 +7,16 @@
background: var(--color-links); background: var(--color-links);
border-radius: 50%; border-radius: 50%;
cursor: var(--custom-cursor, pointer); cursor: var(--custom-cursor, pointer);
transform: scale(1); position: absolute;
left: var(--fill-percentage);
transform: scale(1) translate(-45%, -50%);
transition: transform 0.3s ease-in-out; transition: transform 0.3s ease-in-out;
z-index: 2; z-index: 2;
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
&:hover { &:hover {
transform: scale(1.5); transform: scale(1.5) translate(-30%, -30%);
} }
} }
@ -70,30 +72,6 @@
); );
} }
.slider::before,
.slider::after {
content: '';
position: absolute;
top: 0;
height: 100%;
transition: transform 0.2s ease;
z-index: -1;
transform-origin: left;
}
.slider::before {
left: 0;
background-color: var(--color-links);
transform: scaleX(var(--fill-percentage-before));
}
.slider::after {
right: 0;
background: var(--color-text-secondary);
transform: scaleX(var(--fill-percentage-after));
transform-origin: right;
}
.slider::-webkit-slider-thumb { .slider::-webkit-slider-thumb {
@include thumb-styles(); @include thumb-styles();
} }

View File

@ -51,7 +51,7 @@ export const MEDIA_PROGRESSIVE_CACHE_DISABLED = false;
export const MEDIA_PROGRESSIVE_CACHE_NAME = 'tt-media-progressive'; export const MEDIA_PROGRESSIVE_CACHE_NAME = 'tt-media-progressive';
export const MEDIA_CACHE_MAX_BYTES = 512 * 1024; // 512 KB export const MEDIA_CACHE_MAX_BYTES = 512 * 1024; // 512 KB
export const CUSTOM_BG_CACHE_NAME = 'tt-custom-bg'; export const CUSTOM_BG_CACHE_NAME = 'tt-custom-bg';
export const LANG_CACHE_NAME = 'tt-lang-packs-v40'; export const LANG_CACHE_NAME = 'tt-lang-packs-v42';
export const ASSET_CACHE_NAME = 'tt-assets'; export const ASSET_CACHE_NAME = 'tt-assets';
export const AUTODOWNLOAD_FILESIZE_MB_LIMITS = [1, 5, 10, 50, 100, 500]; export const AUTODOWNLOAD_FILESIZE_MB_LIMITS = [1, 5, 10, 50, 100, 500];
export const DATA_BROADCAST_CHANNEL_NAME = 'tt-global'; export const DATA_BROADCAST_CHANNEL_NAME = 'tt-global';

View File

@ -11,7 +11,11 @@ import { buildQueryString } from '../../../util/requestQuery';
import { extractCurrentThemeParams } from '../../../util/themeStyle'; import { extractCurrentThemeParams } from '../../../util/themeStyle';
import { callApi } from '../../../api/gramjs'; import { callApi } from '../../../api/gramjs';
import { isChatChannel, isChatSuperGroup } from '../../helpers'; import { isChatChannel, isChatSuperGroup } from '../../helpers';
import { getRequestInputInvoice, getStarsTransactionFromGift } from '../../helpers/payments'; import {
getPrizeStarsTransactionFromGiveaway,
getRequestInputInvoice,
getStarsTransactionFromGift,
} from '../../helpers/payments';
import { addActionHandler, getGlobal, setGlobal } from '../../index'; import { addActionHandler, getGlobal, setGlobal } from '../../index';
import { import {
appendStarsTransactions, closeInvoice, appendStarsTransactions, closeInvoice,
@ -457,12 +461,12 @@ addActionHandler('openGiveawayModal', async (global, actions, payload): Promise<
chat, chat,
}); });
if (!result) { const starOptions = await callApi('fetchStarsGiveawayOptions');
if (!result || !starOptions) {
return; return;
} }
global = getGlobal();
const isOpen = Boolean(chatId); const isOpen = Boolean(chatId);
global = updateTabState(global, { global = updateTabState(global, {
@ -471,6 +475,7 @@ addActionHandler('openGiveawayModal', async (global, actions, payload): Promise<
gifts: result, gifts: result,
isOpen, isOpen,
prepaidGiveaway, prepaidGiveaway,
starOptions,
}, },
}, tabId); }, tabId);
setGlobal(global); setGlobal(global);
@ -546,6 +551,22 @@ addActionHandler('openStarsTransactionFromGift', (global, actions, payload): Act
return openStarsTransactionModal(global, transaction, tabId); return openStarsTransactionModal(global, transaction, tabId);
}); });
addActionHandler('openPrizeStarsTransactionFromGiveaway', (global, actions, payload): ActionReturnType => {
const {
chatId,
messageId,
tabId = getCurrentTabId(),
} = payload || {};
const message = selectChatMessage(global, chatId, messageId);
if (!message) return undefined;
const transaction = getPrizeStarsTransactionFromGiveaway(message);
if (!transaction) return undefined;
return openStarsTransactionModal(global, transaction, tabId);
});
addActionHandler('openPremiumGiftModal', async (global, actions, payload): Promise<void> => { addActionHandler('openPremiumGiftModal', async (global, actions, payload): Promise<void> => {
const { const {
forUserIds, tabId = getCurrentTabId(), forUserIds, tabId = getCurrentTabId(),
@ -974,6 +995,41 @@ addActionHandler('launchPrepaidGiveaway', async (global, actions, payload): Prom
actions.openBoostStatistics({ chatId, tabId }); actions.openBoostStatistics({ chatId, tabId });
}); });
addActionHandler('launchPrepaidStarsGiveaway', async (global, actions, payload): Promise<void> => {
const {
chatId, giveawayId, paymentPurpose, tabId = getCurrentTabId(),
} = payload;
const chat = selectChat(global, chatId);
if (!chat) return;
const additionalChannels = paymentPurpose?.additionalChannelIds?.map((id) => selectChat(global, id)).filter(Boolean);
const result = await callApi('launchPrepaidGiveaway', {
chat,
giveawayId,
paymentPurpose: {
type: 'starsgiveaway',
chat,
areWinnersVisible: paymentPurpose?.areWinnersVisible,
additionalChannels,
countries: paymentPurpose?.countries,
prizeDescription: paymentPurpose.prizeDescription,
untilDate: paymentPurpose.untilDate,
currency: paymentPurpose.currency,
amount: paymentPurpose.amount,
stars: paymentPurpose.stars,
users: paymentPurpose.users,
},
});
if (!result) {
return;
}
actions.openBoostStatistics({ chatId, tabId });
});
addActionHandler('loadStarStatus', async (global): Promise<void> => { addActionHandler('loadStarStatus', async (global): Promise<void> => {
const currentStatus = global.stars; const currentStatus = global.stars;
const needsTopupOptions = !currentStatus?.topupOptions; const needsTopupOptions = !currentStatus?.topupOptions;

View File

@ -85,6 +85,36 @@ export function getRequestInputInvoice<T extends GlobalState>(
}; };
} }
if (inputInvoice.type === 'starsgiveaway') {
const {
chatId, additionalChannelIds, amount, currency, untilDate, areWinnersVisible, countries,
isOnlyForNewSubscribers, prizeDescription, stars, users,
} = inputInvoice;
const chat = selectChat(global, chatId);
if (!chat) {
return undefined;
}
const additionalChannels = additionalChannelIds?.map((id) => selectChat(global, id)).filter(Boolean);
return {
type: 'starsgiveaway',
purpose: {
type: 'starsgiveaway',
amount,
currency,
chat,
additionalChannels,
untilDate,
areWinnersVisible,
countries,
isOnlyForNewSubscribers,
prizeDescription,
stars,
users,
},
};
}
if (inputInvoice.type === 'giveaway') { if (inputInvoice.type === 'giveaway') {
const { const {
chatId, additionalChannelIds, amount, currency, option, untilDate, areWinnersVisible, countries, chatId, additionalChannelIds, amount, currency, option, untilDate, areWinnersVisible, countries,
@ -207,3 +237,22 @@ export function getStarsTransactionFromGift(message: ApiMessage): ApiStarsTransa
isMyGift: message.isOutgoing || undefined, isMyGift: message.isOutgoing || undefined,
}; };
} }
export function getPrizeStarsTransactionFromGiveaway(message: ApiMessage): ApiStarsTransaction | undefined {
const { action } = message.content;
if (action?.type !== 'prizeStars') return undefined;
const { transactionId, stars, targetChatId } = action;
return {
id: transactionId!,
stars: stars!,
peer: {
type: 'peer',
id: targetChatId!,
},
date: message.date,
isPrizeStars: true,
};
}

View File

@ -54,7 +54,6 @@ import type {
ApiPostStatistics, ApiPostStatistics,
ApiPremiumGiftCodeOption, ApiPremiumGiftCodeOption,
ApiPremiumPromo, ApiPremiumPromo,
ApiPrepaidGiveaway,
ApiQuickReply, ApiQuickReply,
ApiReaction, ApiReaction,
ApiReactionKey, ApiReactionKey,
@ -64,7 +63,7 @@ import type {
ApiSendMessageAction, ApiSendMessageAction,
ApiSession, ApiSession,
ApiSessionData, ApiSessionData,
ApiSponsoredMessage, ApiSponsoredMessage, ApiStarGiveawayOption,
ApiStarsTransaction, ApiStarsTransaction,
ApiStarTopupOption, ApiStarTopupOption,
ApiStealthMode, ApiStealthMode,
@ -76,6 +75,7 @@ import type {
ApiTimezone, ApiTimezone,
ApiTopic, ApiTopic,
ApiTranscription, ApiTranscription,
ApiTypePrepaidGiveaway,
ApiTypeStoryView, ApiTypeStoryView,
ApiTypingStatus, ApiTypingStatus,
ApiUpdate, ApiUpdate,
@ -716,7 +716,8 @@ export type TabState = {
gifts?: ApiPremiumGiftCodeOption[]; gifts?: ApiPremiumGiftCodeOption[];
selectedMemberIds?: string[]; selectedMemberIds?: string[];
selectedChannelIds?: string[]; selectedChannelIds?: string[];
prepaidGiveaway?: ApiPrepaidGiveaway; prepaidGiveaway?: ApiTypePrepaidGiveaway;
starOptions?: ApiStarGiveawayOption[];
}; };
deleteMessageModal?: { deleteMessageModal?: {
@ -1798,6 +1799,11 @@ export interface ActionPayloads {
messageId: number; messageId: number;
} & WithTabId; } & WithTabId;
closeStarsTransactionModal: WithTabId | undefined; closeStarsTransactionModal: WithTabId | undefined;
openPrizeStarsTransactionFromGiveaway: {
chatId: string;
messageId: number;
} & WithTabId;
closePrizeStarsTransactionFromGiveaway: WithTabId | undefined;
sendCredentialsInfo: { sendCredentialsInfo: {
credentials: ApiCredentials; credentials: ApiCredentials;
} & WithTabId; } & WithTabId;
@ -2239,6 +2245,22 @@ export interface ActionPayloads {
}; };
} & WithTabId; } & WithTabId;
launchPrepaidStarsGiveaway: {
chatId: string;
giveawayId: string;
paymentPurpose: {
additionalChannelIds?: string[];
areWinnersVisible?: boolean;
countries?: string[];
prizeDescription?: string;
untilDate: number;
currency: string;
stars: number;
users: number;
amount: number;
};
} & WithTabId;
loadStarStatus: undefined; loadStarStatus: undefined;
loadStarsTransactions: { loadStarsTransactions: {
type: StarsTransactionType; type: StarsTransactionType;
@ -3248,7 +3270,7 @@ export interface ActionPayloads {
openGiveawayModal: ({ openGiveawayModal: ({
chatId: string; chatId: string;
gifts?: number[] | undefined; gifts?: number[] | undefined;
prepaidGiveaway?: ApiPrepaidGiveaway | undefined; prepaidGiveaway?: ApiTypePrepaidGiveaway | undefined;
} & WithTabId); } & WithTabId);
closeGiveawayModal: WithTabId | undefined; closeGiveawayModal: WithTabId | undefined;

View File

@ -1,6 +1,6 @@
const api = require('./api'); const api = require('./api');
const LAYER = 186; const LAYER = 187;
const tlobjects = {}; const tlobjects = {};
for (const tl of Object.values(api)) { for (const tl of Object.values(api)) {

File diff suppressed because one or more lines are too long

View File

@ -36,7 +36,7 @@ inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector<bytes> s
inputMediaDice#e66fbf7b emoticon:string = InputMedia; inputMediaDice#e66fbf7b emoticon:string = InputMedia;
inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia; inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia;
inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia; inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia;
inputMediaPaidMedia#aa661fc3 stars_amount:long extended_media:Vector<InputMedia> = InputMedia; inputMediaPaidMedia#c4103386 flags:# stars_amount:long extended_media:Vector<InputMedia> payload:flags.0?string = InputMedia;
inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto; inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto;
inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto;
@ -108,8 +108,8 @@ messageMediaGeoLive#b940c666 flags:# geo:GeoPoint heading:flags.0?int period:int
messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia; messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia;
messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia; messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia;
messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia; messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia;
messageMediaGiveaway#daad85b0 flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector<long> countries_iso2:flags.1?Vector<string> prize_description:flags.3?string quantity:int months:int until_date:int = MessageMedia; messageMediaGiveaway#aa073beb flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector<long> countries_iso2:flags.1?Vector<string> prize_description:flags.3?string quantity:int months:flags.4?int stars:flags.5?long until_date:int = MessageMedia;
messageMediaGiveawayResults#c6991068 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector<long> months:int prize_description:flags.1?string until_date:int = MessageMedia; messageMediaGiveawayResults#ceaa3ea1 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector<long> months:flags.4?int stars:flags.5?long prize_description:flags.1?string until_date:int = MessageMedia;
messageMediaPaidMedia#a8852491 stars_amount:long extended_media:Vector<MessageExtendedMedia> = MessageMedia; messageMediaPaidMedia#a8852491 stars_amount:long extended_media:Vector<MessageExtendedMedia> = MessageMedia;
messageActionEmpty#b6aef7b0 = MessageAction; messageActionEmpty#b6aef7b0 = MessageAction;
messageActionChatCreate#bd47cbad title:string users:Vector<long> = MessageAction; messageActionChatCreate#bd47cbad title:string users:Vector<long> = MessageAction;
@ -150,12 +150,13 @@ messageActionSuggestProfilePhoto#57de635e photo:Photo = MessageAction;
messageActionRequestedPeer#31518e9b button_id:int peers:Vector<Peer> = MessageAction; messageActionRequestedPeer#31518e9b button_id:int peers:Vector<Peer> = MessageAction;
messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.1?true wallpaper:WallPaper = MessageAction; messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.1?true wallpaper:WallPaper = MessageAction;
messageActionGiftCode#678c2e09 flags:# via_giveaway:flags.0?true unclaimed:flags.2?true boost_peer:flags.1?Peer months:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long = MessageAction; messageActionGiftCode#678c2e09 flags:# via_giveaway:flags.0?true unclaimed:flags.2?true boost_peer:flags.1?Peer months:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long = MessageAction;
messageActionGiveawayLaunch#332ba9ed = MessageAction; messageActionGiveawayLaunch#a80f51e4 flags:# stars:flags.0?long = MessageAction;
messageActionGiveawayResults#2a9fadc5 winners_count:int unclaimed_count:int = MessageAction; messageActionGiveawayResults#87e2f155 flags:# stars:flags.0?true winners_count:int unclaimed_count:int = MessageAction;
messageActionBoostApply#cc02aa6d boosts:int = MessageAction; messageActionBoostApply#cc02aa6d boosts:int = MessageAction;
messageActionRequestedPeerSentMe#93b31848 button_id:int peers:Vector<RequestedPeer> = MessageAction; messageActionRequestedPeerSentMe#93b31848 button_id:int peers:Vector<RequestedPeer> = MessageAction;
messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_amount:long payload:flags.0?bytes charge:PaymentCharge = MessageAction; messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_amount:long payload:flags.0?bytes charge:PaymentCharge = MessageAction;
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; 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;
dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog;
dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog;
photoEmpty#2331b22d id:long = Photo; photoEmpty#2331b22d id:long = Photo;
@ -369,6 +370,8 @@ updateBroadcastRevenueTransactions#dfd961f5 peer:Peer balances:BroadcastRevenueB
updateStarsBalance#fb85198 balance:long = Update; updateStarsBalance#fb85198 balance:long = Update;
updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long connection_id:string message:Message reply_to_message:flags.2?Message chat_instance:long data:flags.0?bytes = Update; updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long connection_id:string message:Message reply_to_message:flags.2?Message chat_instance:long data:flags.0?bytes = Update;
updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update; updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update;
updateBotPurchasedPaidMedia#283bd312 user_id:long payload:string qts:int = Update;
updatePaidReactionPrivacy#51ca7aec private:Bool = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference;
updates.difference#f49ca0 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> state:updates.State = updates.Difference; updates.difference#f49ca0 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> state:updates.State = updates.Difference;
@ -830,9 +833,10 @@ channelAdminLogEventActionChangeWallpaper#31bb5d52 prev_value:WallPaper new_valu
channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction; channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeEmojiStickerSet#46d840ab prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; channelAdminLogEventActionChangeEmojiStickerSet#46d840ab prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleSignatureProfiles#60a79c79 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionToggleSignatureProfiles#60a79c79 new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionParticipantSubExtend#64642db3 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction;
channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
channels.adminLogResults#ed8af74d events:Vector<ChannelAdminLogEvent> chats:Vector<Chat> users:Vector<User> = channels.AdminLogResults; channels.adminLogResults#ed8af74d events:Vector<ChannelAdminLogEvent> chats:Vector<Chat> users:Vector<User> = channels.AdminLogResults;
channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true = ChannelAdminLogEventsFilter; channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true sub_extend:flags.18?true = ChannelAdminLogEventsFilter;
popularContact#5ce14175 client_id:long importers:int = PopularContact; popularContact#5ce14175 client_id:long importers:int = PopularContact;
messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers;
messages.favedStickers#2cb51097 hash:long packs:Vector<StickerPack> stickers:Vector<Document> = messages.FavedStickers; messages.favedStickers#2cb51097 hash:long packs:Vector<StickerPack> stickers:Vector<Document> = messages.FavedStickers;
@ -1117,6 +1121,7 @@ inputStorePaymentPremiumGiftCode#a3805f3f flags:# users:Vector<InputUser> boost_
inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true boost_peer:InputPeer additional_peers:flags.1?Vector<InputPeer> countries_iso2:flags.2?Vector<string> prize_description:flags.4?string random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose; inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true boost_peer:InputPeer additional_peers:flags.1?Vector<InputPeer> countries_iso2:flags.2?Vector<string> prize_description:flags.4?string random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose;
inputStorePaymentStarsTopup#dddd0f56 stars:long currency:string amount:long = InputStorePaymentPurpose; inputStorePaymentStarsTopup#dddd0f56 stars:long currency:string amount:long = InputStorePaymentPurpose;
inputStorePaymentStarsGift#1d741ef7 user_id:InputUser stars:long currency:string amount:long = InputStorePaymentPurpose; inputStorePaymentStarsGift#1d741ef7 user_id:InputUser stars:long currency:string amount:long = InputStorePaymentPurpose;
inputStorePaymentStarsGiveaway#751f08fa flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true stars:long boost_peer:InputPeer additional_peers:flags.1?Vector<InputPeer> countries_iso2:flags.2?Vector<string> prize_description:flags.4?string random_id:long until_date:int currency:string amount:long users:int = InputStorePaymentPurpose;
premiumGiftOption#74c34319 flags:# months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumGiftOption; premiumGiftOption#74c34319 flags:# months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumGiftOption;
paymentFormMethod#88f8f21b url:string title:string = PaymentFormMethod; paymentFormMethod#88f8f21b url:string title:string = PaymentFormMethod;
emojiStatusEmpty#2de11aae = EmojiStatus; emojiStatusEmpty#2de11aae = EmojiStatus;
@ -1218,9 +1223,10 @@ messages.webPage#fd5e12bd webpage:WebPage chats:Vector<Chat> users:Vector<User>
premiumGiftCodeOption#257e962b flags:# users:int months:int store_product:flags.0?string store_quantity:flags.1?int currency:string amount:long = PremiumGiftCodeOption; premiumGiftCodeOption#257e962b flags:# users:int months:int store_product:flags.0?string store_quantity:flags.1?int currency:string amount:long = PremiumGiftCodeOption;
payments.checkedGiftCode#284a1096 flags:# via_giveaway:flags.2?true from_id:flags.4?Peer giveaway_msg_id:flags.3?int to_id:flags.0?long date:int months:int used_date:flags.1?int chats:Vector<Chat> users:Vector<User> = payments.CheckedGiftCode; payments.checkedGiftCode#284a1096 flags:# via_giveaway:flags.2?true from_id:flags.4?Peer giveaway_msg_id:flags.3?int to_id:flags.0?long date:int months:int used_date:flags.1?int chats:Vector<Chat> users:Vector<User> = payments.CheckedGiftCode;
payments.giveawayInfo#4367daa0 flags:# participating:flags.0?true preparing_results:flags.3?true start_date:int joined_too_early_date:flags.1?int admin_disallowed_chat_id:flags.2?long disallowed_country:flags.4?string = payments.GiveawayInfo; payments.giveawayInfo#4367daa0 flags:# participating:flags.0?true preparing_results:flags.3?true start_date:int joined_too_early_date:flags.1?int admin_disallowed_chat_id:flags.2?long disallowed_country:flags.4?string = payments.GiveawayInfo;
payments.giveawayInfoResults#cd5570 flags:# winner:flags.0?true refunded:flags.1?true start_date:int gift_code_slug:flags.0?string finish_date:int winners_count:int activated_count:int = payments.GiveawayInfo; payments.giveawayInfoResults#e175e66f flags:# winner:flags.0?true refunded:flags.1?true start_date:int gift_code_slug:flags.3?string stars_prize:flags.4?long finish_date:int winners_count:int activated_count:flags.2?int = payments.GiveawayInfo;
prepaidGiveaway#b2539d54 id:long months:int quantity:int date:int = PrepaidGiveaway; prepaidGiveaway#b2539d54 id:long months:int quantity:int date:int = PrepaidGiveaway;
boost#2a1c8c71 flags:# gift:flags.1?true giveaway:flags.2?true unclaimed:flags.3?true id:string user_id:flags.0?long giveaway_msg_id:flags.2?int date:int expires:int used_gift_slug:flags.4?string multiplier:flags.5?int = Boost; prepaidStarsGiveaway#9a9d77e0 id:long stars:long quantity:int boosts:int date:int = PrepaidGiveaway;
boost#4b3e14d6 flags:# gift:flags.1?true giveaway:flags.2?true unclaimed:flags.3?true id:string user_id:flags.0?long giveaway_msg_id:flags.2?int date:int expires:int used_gift_slug:flags.4?string multiplier:flags.5?int stars:flags.6?long = Boost;
premium.boostsList#86f8613c flags:# count:int boosts:Vector<Boost> next_offset:flags.0?string users:Vector<User> = premium.BoostsList; premium.boostsList#86f8613c flags:# count:int boosts:Vector<Boost> next_offset:flags.0?string users:Vector<User> = premium.BoostsList;
myBoost#c448415c flags:# slot:int peer:flags.0?Peer date:int expires:int cooldown_until_date:flags.1?int = MyBoost; myBoost#c448415c flags:# slot:int peer:flags.0?Peer date:int expires:int cooldown_until_date:flags.1?int = MyBoost;
premium.myBoosts#9ae228e2 my_boosts:Vector<MyBoost> chats:Vector<Chat> users:Vector<User> = premium.MyBoosts; premium.myBoosts#9ae228e2 my_boosts:Vector<MyBoost> chats:Vector<Chat> users:Vector<User> = premium.MyBoosts;
@ -1310,7 +1316,7 @@ stats.broadcastRevenueTransactions#87158466 count:int transactions:Vector<Broadc
reactionNotificationsFromContacts#bac3a61a = ReactionNotificationsFrom; reactionNotificationsFromContacts#bac3a61a = ReactionNotificationsFrom;
reactionNotificationsFromAll#4b9e22a0 = ReactionNotificationsFrom; reactionNotificationsFromAll#4b9e22a0 = ReactionNotificationsFrom;
reactionsNotifySettings#56e34970 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings; reactionsNotifySettings#56e34970 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings;
broadcastRevenueBalances#8438f1c6 current_balance:long available_balance:long overall_revenue:long = BroadcastRevenueBalances; broadcastRevenueBalances#c3ff71e7 flags:# withdrawal_enabled:flags.0?true current_balance:long available_balance:long overall_revenue:long = BroadcastRevenueBalances;
availableEffect#93c3e27e flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect; availableEffect#93c3e27e flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect;
messages.availableEffectsNotModified#d1ed9a5b = messages.AvailableEffects; messages.availableEffectsNotModified#d1ed9a5b = messages.AvailableEffects;
messages.availableEffects#bddb616e hash:int effects:Vector<AvailableEffect> documents:Vector<Document> = messages.AvailableEffects; messages.availableEffects#bddb616e hash:int effects:Vector<AvailableEffect> documents:Vector<Document> = messages.AvailableEffects;
@ -1323,7 +1329,7 @@ starsTransactionPeerFragment#e92fd902 = StarsTransactionPeer;
starsTransactionPeer#d80da15d peer:Peer = StarsTransactionPeer; starsTransactionPeer#d80da15d peer:Peer = StarsTransactionPeer;
starsTransactionPeerAds#60682812 = StarsTransactionPeer; starsTransactionPeerAds#60682812 = StarsTransactionPeer;
starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption; starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption;
starsTransaction#433aeb2b flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true id:string stars:long date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector<MessageMedia> subscription_period:flags.12?int = StarsTransaction; starsTransaction#ee7522d5 flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true id:string stars:long date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector<MessageMedia> subscription_period:flags.12?int giveaway_post_id:flags.13?int = StarsTransaction;
payments.starsStatus#bbfa316c flags:# balance:long subscriptions:flags.1?Vector<StarsSubscription> subscriptions_next_offset:flags.2?string subscriptions_missing_balance:flags.4?long history:flags.3?Vector<StarsTransaction> next_offset:flags.0?string chats:Vector<Chat> users:Vector<User> = payments.StarsStatus; payments.starsStatus#bbfa316c flags:# balance:long subscriptions:flags.1?Vector<StarsSubscription> subscriptions_next_offset:flags.2?string subscriptions_missing_balance:flags.4?long history:flags.3?Vector<StarsTransaction> next_offset:flags.0?string chats:Vector<Chat> users:Vector<User> = payments.StarsStatus;
foundStory#e87acbc0 peer:Peer story:StoryItem = FoundStory; foundStory#e87acbc0 peer:Peer story:StoryItem = FoundStory;
stories.foundStories#e2de7737 flags:# count:int stories:Vector<FoundStory> next_offset:flags.0?string chats:Vector<Chat> users:Vector<User> = stories.FoundStories; stories.foundStories#e2de7737 flags:# count:int stories:Vector<FoundStory> next_offset:flags.0?string chats:Vector<Chat> users:Vector<User> = stories.FoundStories;
@ -1340,6 +1346,8 @@ bots.previewInfo#ca71d64 media:Vector<BotPreviewMedia> lang_codes:Vector<string>
starsSubscriptionPricing#5416d58 period:int amount:long = StarsSubscriptionPricing; starsSubscriptionPricing#5416d58 period:int amount:long = StarsSubscriptionPricing;
starsSubscription#538ecf18 flags:# canceled:flags.0?true can_refulfill:flags.1?true missing_balance:flags.2?true id:string peer:Peer until_date:int pricing:StarsSubscriptionPricing chat_invite_hash:flags.3?string = StarsSubscription; starsSubscription#538ecf18 flags:# canceled:flags.0?true can_refulfill:flags.1?true missing_balance:flags.2?true id:string peer:Peer until_date:int pricing:StarsSubscriptionPricing chat_invite_hash:flags.3?string = StarsSubscription;
messageReactor#4ba3a95a flags:# top:flags.0?true my:flags.1?true anonymous:flags.2?true peer_id:flags.3?Peer count:int = MessageReactor; messageReactor#4ba3a95a flags:# top:flags.0?true my:flags.1?true anonymous:flags.2?true peer_id:flags.3?Peer count:int = MessageReactor;
starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true stars:long yearly_boosts:int store_product:flags.2?string currency:string amount:long winners:Vector<StarsGiveawayWinnersOption> = StarsGiveawayOption;
starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption;
---functions--- ---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X; initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X;
@ -1643,6 +1651,7 @@ payments.sendStarsForm#2bb731d flags:# form_id:long invoice:InputInvoice = payme
payments.refundStarsCharge#25ae8f4a user_id:InputUser charge_id:string = Updates; payments.refundStarsCharge#25ae8f4a user_id:InputUser charge_id:string = Updates;
payments.getStarsTransactionsByID#27842d2e peer:InputPeer id:Vector<InputStarsTransaction> = payments.StarsStatus; payments.getStarsTransactionsByID#27842d2e peer:InputPeer id:Vector<InputStarsTransaction> = payments.StarsStatus;
payments.getStarsGiftOptions#d3c96bc8 flags:# user_id:flags.0?InputUser = Vector<StarsGiftOption>; payments.getStarsGiftOptions#d3c96bc8 flags:# user_id:flags.0?InputUser = Vector<StarsGiftOption>;
payments.getStarsGiveawayOptions#bd1efd3e = Vector<StarsGiveawayOption>;
phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall;

View File

@ -368,6 +368,7 @@
"payments.getStarsTransactionsByID", "payments.getStarsTransactionsByID",
"payments.sendStarsForm", "payments.sendStarsForm",
"payments.getStarsGiftOptions", "payments.getStarsGiftOptions",
"payments.getStarsGiveawayOptions",
"payments.refundStarsCharge", "payments.refundStarsCharge",
"payments.getStarsGiftOptions", "payments.getStarsGiftOptions",
"fragment.getCollectibleInfo" "fragment.getCollectibleInfo"

View File

@ -45,7 +45,7 @@ inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector<bytes> s
inputMediaDice#e66fbf7b emoticon:string = InputMedia; inputMediaDice#e66fbf7b emoticon:string = InputMedia;
inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia; inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia;
inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia; inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia;
inputMediaPaidMedia#aa661fc3 stars_amount:long extended_media:Vector<InputMedia> = InputMedia; inputMediaPaidMedia#c4103386 flags:# stars_amount:long extended_media:Vector<InputMedia> payload:flags.0?string = InputMedia;
inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto; inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto;
@ -133,8 +133,8 @@ messageMediaGeoLive#b940c666 flags:# geo:GeoPoint heading:flags.0?int period:int
messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia; messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia;
messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia; messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia;
messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia; messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia;
messageMediaGiveaway#daad85b0 flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector<long> countries_iso2:flags.1?Vector<string> prize_description:flags.3?string quantity:int months:int until_date:int = MessageMedia; messageMediaGiveaway#aa073beb flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector<long> countries_iso2:flags.1?Vector<string> prize_description:flags.3?string quantity:int months:flags.4?int stars:flags.5?long until_date:int = MessageMedia;
messageMediaGiveawayResults#c6991068 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector<long> months:int prize_description:flags.1?string until_date:int = MessageMedia; messageMediaGiveawayResults#ceaa3ea1 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector<long> months:flags.4?int stars:flags.5?long prize_description:flags.1?string until_date:int = MessageMedia;
messageMediaPaidMedia#a8852491 stars_amount:long extended_media:Vector<MessageExtendedMedia> = MessageMedia; messageMediaPaidMedia#a8852491 stars_amount:long extended_media:Vector<MessageExtendedMedia> = MessageMedia;
messageActionEmpty#b6aef7b0 = MessageAction; messageActionEmpty#b6aef7b0 = MessageAction;
@ -176,12 +176,13 @@ messageActionSuggestProfilePhoto#57de635e photo:Photo = MessageAction;
messageActionRequestedPeer#31518e9b button_id:int peers:Vector<Peer> = MessageAction; messageActionRequestedPeer#31518e9b button_id:int peers:Vector<Peer> = MessageAction;
messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.1?true wallpaper:WallPaper = MessageAction; messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.1?true wallpaper:WallPaper = MessageAction;
messageActionGiftCode#678c2e09 flags:# via_giveaway:flags.0?true unclaimed:flags.2?true boost_peer:flags.1?Peer months:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long = MessageAction; messageActionGiftCode#678c2e09 flags:# via_giveaway:flags.0?true unclaimed:flags.2?true boost_peer:flags.1?Peer months:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long = MessageAction;
messageActionGiveawayLaunch#332ba9ed = MessageAction; messageActionGiveawayLaunch#a80f51e4 flags:# stars:flags.0?long = MessageAction;
messageActionGiveawayResults#2a9fadc5 winners_count:int unclaimed_count:int = MessageAction; messageActionGiveawayResults#87e2f155 flags:# stars:flags.0?true winners_count:int unclaimed_count:int = MessageAction;
messageActionBoostApply#cc02aa6d boosts:int = MessageAction; messageActionBoostApply#cc02aa6d boosts:int = MessageAction;
messageActionRequestedPeerSentMe#93b31848 button_id:int peers:Vector<RequestedPeer> = MessageAction; messageActionRequestedPeerSentMe#93b31848 button_id:int peers:Vector<RequestedPeer> = MessageAction;
messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_amount:long payload:flags.0?bytes charge:PaymentCharge = MessageAction; messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_amount:long payload:flags.0?bytes charge:PaymentCharge = MessageAction;
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; 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;
dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog;
dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog;
@ -422,6 +423,8 @@ updateBroadcastRevenueTransactions#dfd961f5 peer:Peer balances:BroadcastRevenueB
updateStarsBalance#fb85198 balance:long = Update; updateStarsBalance#fb85198 balance:long = Update;
updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long connection_id:string message:Message reply_to_message:flags.2?Message chat_instance:long data:flags.0?bytes = Update; updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long connection_id:string message:Message reply_to_message:flags.2?Message chat_instance:long data:flags.0?bytes = Update;
updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update; updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update;
updateBotPurchasedPaidMedia#283bd312 user_id:long payload:string qts:int = Update;
updatePaidReactionPrivacy#51ca7aec private:Bool = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@ -1013,12 +1016,13 @@ channelAdminLogEventActionChangeWallpaper#31bb5d52 prev_value:WallPaper new_valu
channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction; channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeEmojiStickerSet#46d840ab prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; channelAdminLogEventActionChangeEmojiStickerSet#46d840ab prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleSignatureProfiles#60a79c79 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionToggleSignatureProfiles#60a79c79 new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionParticipantSubExtend#64642db3 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction;
channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
channels.adminLogResults#ed8af74d events:Vector<ChannelAdminLogEvent> chats:Vector<Chat> users:Vector<User> = channels.AdminLogResults; channels.adminLogResults#ed8af74d events:Vector<ChannelAdminLogEvent> chats:Vector<Chat> users:Vector<User> = channels.AdminLogResults;
channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true = ChannelAdminLogEventsFilter; channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true sub_extend:flags.18?true = ChannelAdminLogEventsFilter;
popularContact#5ce14175 client_id:long importers:int = PopularContact; popularContact#5ce14175 client_id:long importers:int = PopularContact;
@ -1472,6 +1476,7 @@ inputStorePaymentPremiumGiftCode#a3805f3f flags:# users:Vector<InputUser> boost_
inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true boost_peer:InputPeer additional_peers:flags.1?Vector<InputPeer> countries_iso2:flags.2?Vector<string> prize_description:flags.4?string random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose; inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true boost_peer:InputPeer additional_peers:flags.1?Vector<InputPeer> countries_iso2:flags.2?Vector<string> prize_description:flags.4?string random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose;
inputStorePaymentStarsTopup#dddd0f56 stars:long currency:string amount:long = InputStorePaymentPurpose; inputStorePaymentStarsTopup#dddd0f56 stars:long currency:string amount:long = InputStorePaymentPurpose;
inputStorePaymentStarsGift#1d741ef7 user_id:InputUser stars:long currency:string amount:long = InputStorePaymentPurpose; inputStorePaymentStarsGift#1d741ef7 user_id:InputUser stars:long currency:string amount:long = InputStorePaymentPurpose;
inputStorePaymentStarsGiveaway#751f08fa flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true stars:long boost_peer:InputPeer additional_peers:flags.1?Vector<InputPeer> countries_iso2:flags.2?Vector<string> prize_description:flags.4?string random_id:long until_date:int currency:string amount:long users:int = InputStorePaymentPurpose;
premiumGiftOption#74c34319 flags:# months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumGiftOption; premiumGiftOption#74c34319 flags:# months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumGiftOption;
@ -1633,11 +1638,12 @@ premiumGiftCodeOption#257e962b flags:# users:int months:int store_product:flags.
payments.checkedGiftCode#284a1096 flags:# via_giveaway:flags.2?true from_id:flags.4?Peer giveaway_msg_id:flags.3?int to_id:flags.0?long date:int months:int used_date:flags.1?int chats:Vector<Chat> users:Vector<User> = payments.CheckedGiftCode; payments.checkedGiftCode#284a1096 flags:# via_giveaway:flags.2?true from_id:flags.4?Peer giveaway_msg_id:flags.3?int to_id:flags.0?long date:int months:int used_date:flags.1?int chats:Vector<Chat> users:Vector<User> = payments.CheckedGiftCode;
payments.giveawayInfo#4367daa0 flags:# participating:flags.0?true preparing_results:flags.3?true start_date:int joined_too_early_date:flags.1?int admin_disallowed_chat_id:flags.2?long disallowed_country:flags.4?string = payments.GiveawayInfo; payments.giveawayInfo#4367daa0 flags:# participating:flags.0?true preparing_results:flags.3?true start_date:int joined_too_early_date:flags.1?int admin_disallowed_chat_id:flags.2?long disallowed_country:flags.4?string = payments.GiveawayInfo;
payments.giveawayInfoResults#cd5570 flags:# winner:flags.0?true refunded:flags.1?true start_date:int gift_code_slug:flags.0?string finish_date:int winners_count:int activated_count:int = payments.GiveawayInfo; payments.giveawayInfoResults#e175e66f flags:# winner:flags.0?true refunded:flags.1?true start_date:int gift_code_slug:flags.3?string stars_prize:flags.4?long finish_date:int winners_count:int activated_count:flags.2?int = payments.GiveawayInfo;
prepaidGiveaway#b2539d54 id:long months:int quantity:int date:int = PrepaidGiveaway; prepaidGiveaway#b2539d54 id:long months:int quantity:int date:int = PrepaidGiveaway;
prepaidStarsGiveaway#9a9d77e0 id:long stars:long quantity:int boosts:int date:int = PrepaidGiveaway;
boost#2a1c8c71 flags:# gift:flags.1?true giveaway:flags.2?true unclaimed:flags.3?true id:string user_id:flags.0?long giveaway_msg_id:flags.2?int date:int expires:int used_gift_slug:flags.4?string multiplier:flags.5?int = Boost; boost#4b3e14d6 flags:# gift:flags.1?true giveaway:flags.2?true unclaimed:flags.3?true id:string user_id:flags.0?long giveaway_msg_id:flags.2?int date:int expires:int used_gift_slug:flags.4?string multiplier:flags.5?int stars:flags.6?long = Boost;
premium.boostsList#86f8613c flags:# count:int boosts:Vector<Boost> next_offset:flags.0?string users:Vector<User> = premium.BoostsList; premium.boostsList#86f8613c flags:# count:int boosts:Vector<Boost> next_offset:flags.0?string users:Vector<User> = premium.BoostsList;
@ -1795,7 +1801,7 @@ reactionNotificationsFromAll#4b9e22a0 = ReactionNotificationsFrom;
reactionsNotifySettings#56e34970 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings; reactionsNotifySettings#56e34970 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings;
broadcastRevenueBalances#8438f1c6 current_balance:long available_balance:long overall_revenue:long = BroadcastRevenueBalances; broadcastRevenueBalances#c3ff71e7 flags:# withdrawal_enabled:flags.0?true current_balance:long available_balance:long overall_revenue:long = BroadcastRevenueBalances;
availableEffect#93c3e27e flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect; availableEffect#93c3e27e flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect;
@ -1814,7 +1820,7 @@ starsTransactionPeerAds#60682812 = StarsTransactionPeer;
starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption; starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption;
starsTransaction#433aeb2b flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true id:string stars:long date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector<MessageMedia> subscription_period:flags.12?int = StarsTransaction; starsTransaction#ee7522d5 flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true id:string stars:long date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector<MessageMedia> subscription_period:flags.12?int giveaway_post_id:flags.13?int = StarsTransaction;
payments.starsStatus#bbfa316c flags:# balance:long subscriptions:flags.1?Vector<StarsSubscription> subscriptions_next_offset:flags.2?string subscriptions_missing_balance:flags.4?long history:flags.3?Vector<StarsTransaction> next_offset:flags.0?string chats:Vector<Chat> users:Vector<User> = payments.StarsStatus; payments.starsStatus#bbfa316c flags:# balance:long subscriptions:flags.1?Vector<StarsSubscription> subscriptions_next_offset:flags.2?string subscriptions_missing_balance:flags.4?long history:flags.3?Vector<StarsTransaction> next_offset:flags.0?string chats:Vector<Chat> users:Vector<User> = payments.StarsStatus;
@ -1848,6 +1854,10 @@ starsSubscription#538ecf18 flags:# canceled:flags.0?true can_refulfill:flags.1?t
messageReactor#4ba3a95a flags:# top:flags.0?true my:flags.1?true anonymous:flags.2?true peer_id:flags.3?Peer count:int = MessageReactor; messageReactor#4ba3a95a flags:# top:flags.0?true my:flags.1?true anonymous:flags.2?true peer_id:flags.3?Peer count:int = MessageReactor;
starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true stars:long yearly_boosts:int store_product:flags.2?string currency:string amount:long winners:Vector<StarsGiveawayWinnersOption> = StarsGiveawayOption;
starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption;
---functions--- ---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@ -2244,8 +2254,9 @@ messages.editFactCheck#589ee75 peer:InputPeer msg_id:int text:TextWithEntities =
messages.deleteFactCheck#d1da940c peer:InputPeer msg_id:int = Updates; messages.deleteFactCheck#d1da940c peer:InputPeer msg_id:int = Updates;
messages.getFactCheck#b9cdc5ee peer:InputPeer msg_id:Vector<int> = Vector<FactCheck>; messages.getFactCheck#b9cdc5ee peer:InputPeer msg_id:Vector<int> = Vector<FactCheck>;
messages.requestMainWebView#c9e01e7b flags:# compact:flags.7?true peer:InputPeer bot:InputUser start_param:flags.1?string theme_params:flags.0?DataJSON platform:string = WebViewResult; messages.requestMainWebView#c9e01e7b flags:# compact:flags.7?true peer:InputPeer bot:InputUser start_param:flags.1?string theme_params:flags.0?DataJSON platform:string = WebViewResult;
messages.sendPaidReaction#25c8fe3e flags:# private:flags.0?true peer:InputPeer msg_id:int count:int random_id:long = Updates; messages.sendPaidReaction#9dd6a67b flags:# peer:InputPeer msg_id:int count:int random_id:long private:flags.0?Bool = Updates;
messages.togglePaidReactionPrivacy#849ad397 peer:InputPeer msg_id:int private:Bool = Bool; messages.togglePaidReactionPrivacy#849ad397 peer:InputPeer msg_id:int private:Bool = Bool;
messages.getPaidReactionPrivacy#472455aa = Updates;
updates.getState#edd4882a = updates.State; updates.getState#edd4882a = updates.State;
updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference;
@ -2411,6 +2422,7 @@ payments.getStarsGiftOptions#d3c96bc8 flags:# user_id:flags.0?InputUser = Vector
payments.getStarsSubscriptions#32512c5 flags:# missing_balance:flags.0?true peer:InputPeer offset:string = payments.StarsStatus; payments.getStarsSubscriptions#32512c5 flags:# missing_balance:flags.0?true peer:InputPeer offset:string = payments.StarsStatus;
payments.changeStarsSubscription#c7770878 flags:# peer:InputPeer subscription_id:string canceled:flags.0?Bool = Bool; payments.changeStarsSubscription#c7770878 flags:# peer:InputPeer subscription_id:string canceled:flags.0?Bool = Bool;
payments.fulfillStarsSubscription#cc5bebb3 peer:InputPeer subscription_id:string = Bool; payments.fulfillStarsSubscription#cc5bebb3 peer:InputPeer subscription_id:string = Bool;
payments.getStarsGiveawayOptions#bd1efd3e = Vector<StarsGiveawayOption>;
stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector<InputStickerSetItem> software:flags.3?string = messages.StickerSet; stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector<InputStickerSetItem> software:flags.3?string = messages.StickerSet;
stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet;

View File

@ -514,14 +514,16 @@ export type InlineBotSettings = {
}; };
export type CustomPeerType = 'premium' | 'toBeDistributed' | 'contacts' | 'nonContacts' export type CustomPeerType = 'premium' | 'toBeDistributed' | 'contacts' | 'nonContacts'
| 'groups' | 'channels' | 'bots' | 'excludeMuted' | 'excludeArchived' | 'excludeRead'; | 'groups' | 'channels' | 'bots' | 'excludeMuted' | 'excludeArchived' | 'excludeRead' | 'stars';
export interface CustomPeer { export interface CustomPeer {
isCustomPeer: true; isCustomPeer: true;
key?: string | number;
titleKey: string; titleKey: string;
subtitleKey?: string; subtitleKey?: string;
avatarIcon: IconName; avatarIcon: IconName;
isAvatarSquare?: boolean; isAvatarSquare?: boolean;
titleValue?: number;
peerColorId?: number; peerColorId?: number;
customPeerAvatarColor?: string; customPeerAvatarColor?: string;
withPremiumGradient?: boolean; withPremiumGradient?: boolean;

View File

@ -1539,6 +1539,9 @@ export interface LangPair {
'GiftStarsOutgoing': { 'GiftStarsOutgoing': {
'user': string | number; 'user': string | number;
}; };
'PrizeCredits': {
'count': string | number;
};
} }
export type LangKey = keyof LangPair; export type LangKey = keyof LangPair;

View File

@ -18,6 +18,14 @@ export const CUSTOM_PEER_TO_BE_DISTRIBUTED: UniqueCustomPeer = {
withPremiumGradient: true, withPremiumGradient: true,
}; };
export const CUSTOM_PEER_STAR: UniqueCustomPeer = {
isCustomPeer: true,
type: 'stars',
titleKey: 'Stars',
avatarIcon: 'star',
peerColorId: 1,
};
export const CUSTOM_PEER_INCLUDED_CHAT_TYPES: UniqueCustomPeer[] = [ export const CUSTOM_PEER_INCLUDED_CHAT_TYPES: UniqueCustomPeer[] = [
{ {
isCustomPeer: true, isCustomPeer: true,