Star gift: Support auction (#6541)
This commit is contained in:
parent
ef773026c0
commit
38d7cd0c5a
@ -1,6 +1,7 @@
|
|||||||
import { Api as GramJs } from '../../../lib/gramjs';
|
import { Api as GramJs } from '../../../lib/gramjs';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
|
ApiAuctionBidLevel,
|
||||||
ApiDisallowedGiftsSettings,
|
ApiDisallowedGiftsSettings,
|
||||||
ApiInputSavedStarGift,
|
ApiInputSavedStarGift,
|
||||||
ApiSavedStarGift,
|
ApiSavedStarGift,
|
||||||
@ -8,10 +9,14 @@ import type {
|
|||||||
ApiStarGiftAttribute,
|
ApiStarGiftAttribute,
|
||||||
ApiStarGiftAttributeCounter,
|
ApiStarGiftAttributeCounter,
|
||||||
ApiStarGiftAttributeId,
|
ApiStarGiftAttributeId,
|
||||||
|
ApiStarGiftAuctionAcquiredGift,
|
||||||
|
ApiStarGiftAuctionState,
|
||||||
|
ApiStarGiftAuctionUserState,
|
||||||
ApiStarGiftCollection,
|
ApiStarGiftCollection,
|
||||||
ApiStarGiftUpgradePreview,
|
ApiStarGiftUpgradePreview,
|
||||||
ApiStarGiftUpgradePrice,
|
ApiStarGiftUpgradePrice,
|
||||||
ApiTypeResaleStarGifts,
|
ApiTypeResaleStarGifts,
|
||||||
|
ApiTypeStarGiftAuctionState,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
|
|
||||||
import { int2hex } from '../../../util/colors';
|
import { int2hex } from '../../../util/colors';
|
||||||
@ -20,6 +25,7 @@ import { buildApiChatFromPreview } from '../apiBuilders/chats';
|
|||||||
import { addDocumentToLocalDb } from '../helpers/localDb';
|
import { addDocumentToLocalDb } from '../helpers/localDb';
|
||||||
import { buildApiFormattedText } from './common';
|
import { buildApiFormattedText } from './common';
|
||||||
import { buildApiCurrencyAmount } from './payments';
|
import { buildApiCurrencyAmount } from './payments';
|
||||||
|
import { buildApiPeerId } from './peers';
|
||||||
import { getApiChatIdFromMtpPeer } from './peers';
|
import { getApiChatIdFromMtpPeer } from './peers';
|
||||||
import { buildStickerFromDocument } from './symbols';
|
import { buildStickerFromDocument } from './symbols';
|
||||||
import { buildApiUser } from './users';
|
import { buildApiUser } from './users';
|
||||||
@ -57,7 +63,7 @@ export function buildApiStarGift(starGift: GramJs.TypeStarGift): ApiStarGift {
|
|||||||
const {
|
const {
|
||||||
id, limited, stars, availabilityRemains, availabilityTotal, convertStars, firstSaleDate, lastSaleDate, soldOut,
|
id, limited, stars, availabilityRemains, availabilityTotal, convertStars, firstSaleDate, lastSaleDate, soldOut,
|
||||||
birthday, upgradeStars, resellMinStars, title, availabilityResale, releasedBy,
|
birthday, upgradeStars, resellMinStars, title, availabilityResale, releasedBy,
|
||||||
requirePremium, limitedPerUser, perUserTotal, perUserRemains, lockedUntilDate,
|
requirePremium, limitedPerUser, perUserTotal, perUserRemains, lockedUntilDate, auction, giftsPerRound, background,
|
||||||
} = starGift;
|
} = starGift;
|
||||||
|
|
||||||
addDocumentToLocalDb(starGift.sticker);
|
addDocumentToLocalDb(starGift.sticker);
|
||||||
@ -87,6 +93,13 @@ export function buildApiStarGift(starGift: GramJs.TypeStarGift): ApiStarGift {
|
|||||||
perUserTotal,
|
perUserTotal,
|
||||||
perUserRemains,
|
perUserRemains,
|
||||||
lockedUntilDate,
|
lockedUntilDate,
|
||||||
|
isAuction: auction,
|
||||||
|
giftsPerRound,
|
||||||
|
background: background ? {
|
||||||
|
centerColor: int2hex(background.centerColor),
|
||||||
|
edgeColor: int2hex(background.edgeColor),
|
||||||
|
textColor: int2hex(background.textColor),
|
||||||
|
} : undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,8 +172,9 @@ export function buildApiStarGiftAttribute(attribute: GramJs.TypeStarGiftAttribut
|
|||||||
|
|
||||||
export function buildApiSavedStarGift(userStarGift: GramJs.SavedStarGift, peerId: string): ApiSavedStarGift {
|
export function buildApiSavedStarGift(userStarGift: GramJs.SavedStarGift, peerId: string): ApiSavedStarGift {
|
||||||
const {
|
const {
|
||||||
gift, date, convertStars, fromId, message, msgId, nameHidden, unsaved, upgradeStars, transferStars, canUpgrade,
|
gift, date, convertStars, fromId, message, msgId, nameHidden, unsaved, refunded, upgradeStars, transferStars,
|
||||||
savedId, canExportAt, pinnedToTop, canResellAt, canTransferAt, prepaidUpgradeHash, dropOriginalDetailsStars,
|
canUpgrade, savedId, canExportAt, pinnedToTop, canResellAt, canTransferAt, prepaidUpgradeHash,
|
||||||
|
dropOriginalDetailsStars,
|
||||||
} = userStarGift;
|
} = userStarGift;
|
||||||
|
|
||||||
const inputGift: ApiInputSavedStarGift | undefined = savedId && peerId
|
const inputGift: ApiInputSavedStarGift | undefined = savedId && peerId
|
||||||
@ -176,6 +190,7 @@ export function buildApiSavedStarGift(userStarGift: GramJs.SavedStarGift, peerId
|
|||||||
messageId: msgId,
|
messageId: msgId,
|
||||||
isNameHidden: nameHidden,
|
isNameHidden: nameHidden,
|
||||||
isUnsaved: unsaved,
|
isUnsaved: unsaved,
|
||||||
|
isRefunded: refunded,
|
||||||
canUpgrade,
|
canUpgrade,
|
||||||
alreadyPaidUpgradeStars: toJSNumber(upgradeStars),
|
alreadyPaidUpgradeStars: toJSNumber(upgradeStars),
|
||||||
transferStars: toJSNumber(transferStars),
|
transferStars: toJSNumber(transferStars),
|
||||||
@ -334,3 +349,104 @@ export function buildApiStarGiftUpgradePreview(
|
|||||||
nextPrices: result.nextPrices?.map(buildApiStarGiftUpgradePrice) || [],
|
nextPrices: result.nextPrices?.map(buildApiStarGiftUpgradePrice) || [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function buildApiAuctionBidLevel(bidLevel: GramJs.AuctionBidLevel): ApiAuctionBidLevel {
|
||||||
|
return {
|
||||||
|
pos: bidLevel.pos,
|
||||||
|
amount: toJSNumber(bidLevel.amount) ?? 0,
|
||||||
|
date: bidLevel.date,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildApiTypeStarGiftAuctionState(
|
||||||
|
state: GramJs.TypeStarGiftAuctionState,
|
||||||
|
): ApiTypeStarGiftAuctionState | undefined {
|
||||||
|
if (state instanceof GramJs.StarGiftAuctionStateNotModified) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state instanceof GramJs.StarGiftAuctionStateFinished) {
|
||||||
|
const {
|
||||||
|
startDate, endDate, averagePrice, listedCount, fragmentListedCount, fragmentListedUrl,
|
||||||
|
} = state;
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'finished',
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
averagePrice: toJSNumber(averagePrice),
|
||||||
|
listedCount,
|
||||||
|
fragmentListedCount,
|
||||||
|
fragmentListedUrl,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
version, startDate, endDate, minBidAmount, bidLevels, topBidders,
|
||||||
|
nextRoundAt, lastGiftNum, giftsLeft, currentRound, totalRounds,
|
||||||
|
} = state;
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'active',
|
||||||
|
version,
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
minBidAmount: toJSNumber(minBidAmount),
|
||||||
|
bidLevels: bidLevels.map(buildApiAuctionBidLevel),
|
||||||
|
topBidders: topBidders.map((id) => buildApiPeerId(id, 'user')),
|
||||||
|
nextRoundAt,
|
||||||
|
lastGiftNum,
|
||||||
|
giftsLeft,
|
||||||
|
currentRound,
|
||||||
|
totalRounds,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildApiStarGiftAuctionUserState(
|
||||||
|
userState: GramJs.StarGiftAuctionUserState,
|
||||||
|
): ApiStarGiftAuctionUserState {
|
||||||
|
const {
|
||||||
|
returned, bidAmount, bidDate, minBidAmount, bidPeer, acquiredCount,
|
||||||
|
} = userState;
|
||||||
|
|
||||||
|
return {
|
||||||
|
isReturned: returned || undefined,
|
||||||
|
bidAmount: bidAmount !== undefined ? toJSNumber(bidAmount) : undefined,
|
||||||
|
bidDate,
|
||||||
|
minBidAmount: minBidAmount !== undefined ? toJSNumber(minBidAmount) : undefined,
|
||||||
|
bidPeerId: bidPeer && getApiChatIdFromMtpPeer(bidPeer),
|
||||||
|
acquiredCount,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildApiStarGiftAuctionState(
|
||||||
|
result: GramJs.payments.StarGiftAuctionState,
|
||||||
|
): ApiStarGiftAuctionState | undefined {
|
||||||
|
const gift = buildApiStarGift(result.gift);
|
||||||
|
if (gift.type !== 'starGift') return undefined;
|
||||||
|
|
||||||
|
const state = buildApiTypeStarGiftAuctionState(result.state);
|
||||||
|
if (!state) return undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
gift,
|
||||||
|
state,
|
||||||
|
userState: buildApiStarGiftAuctionUserState(result.userState),
|
||||||
|
timeout: result.timeout,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildApiStarGiftAuctionAcquiredGift(
|
||||||
|
result: GramJs.StarGiftAuctionAcquiredGift,
|
||||||
|
): ApiStarGiftAuctionAcquiredGift {
|
||||||
|
return {
|
||||||
|
peerId: getApiChatIdFromMtpPeer(result.peer),
|
||||||
|
date: result.date,
|
||||||
|
bidAmount: toJSNumber(result.bidAmount),
|
||||||
|
round: result.round,
|
||||||
|
position: result.pos,
|
||||||
|
message: result.message ? buildApiFormattedText(result.message) : undefined,
|
||||||
|
giftNumber: result.giftNum,
|
||||||
|
isNameHidden: result.nameHidden || undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@ -390,8 +390,9 @@ export function buildApiMessageAction(action: GramJs.TypeMessageAction): ApiMess
|
|||||||
}
|
}
|
||||||
if (action instanceof GramJs.MessageActionStarGift) {
|
if (action instanceof GramJs.MessageActionStarGift) {
|
||||||
const {
|
const {
|
||||||
nameHidden, saved, converted, upgraded, refunded, canUpgrade, prepaidUpgrade, gift, message, convertStars,
|
nameHidden, saved, converted, upgraded, refunded, canUpgrade, prepaidUpgrade, auctionAcquired,
|
||||||
upgradeMsgId, giftMsgId, upgradeStars, fromId, peer, savedId, prepaidUpgradeHash,
|
gift, message, convertStars, upgradeMsgId, giftMsgId, upgradeStars, fromId, peer, savedId,
|
||||||
|
prepaidUpgradeHash, toId, giftNum,
|
||||||
} = action;
|
} = action;
|
||||||
|
|
||||||
const starGift = buildApiStarGift(gift);
|
const starGift = buildApiStarGift(gift);
|
||||||
@ -407,6 +408,7 @@ export function buildApiMessageAction(action: GramJs.TypeMessageAction): ApiMess
|
|||||||
isRefunded: refunded,
|
isRefunded: refunded,
|
||||||
canUpgrade,
|
canUpgrade,
|
||||||
isPrepaidUpgrade: prepaidUpgrade,
|
isPrepaidUpgrade: prepaidUpgrade,
|
||||||
|
isAuctionAcquired: auctionAcquired,
|
||||||
gift: starGift,
|
gift: starGift,
|
||||||
message: message && buildApiFormattedText(message),
|
message: message && buildApiFormattedText(message),
|
||||||
starsToConvert: toJSNumber(convertStars),
|
starsToConvert: toJSNumber(convertStars),
|
||||||
@ -417,6 +419,8 @@ export function buildApiMessageAction(action: GramJs.TypeMessageAction): ApiMess
|
|||||||
peerId: peer && getApiChatIdFromMtpPeer(peer),
|
peerId: peer && getApiChatIdFromMtpPeer(peer),
|
||||||
savedId: savedId !== undefined ? buildApiPeerId(savedId, 'user') : undefined,
|
savedId: savedId !== undefined ? buildApiPeerId(savedId, 'user') : undefined,
|
||||||
prepaidUpgradeHash,
|
prepaidUpgradeHash,
|
||||||
|
toId: toId && getApiChatIdFromMtpPeer(toId),
|
||||||
|
giftNumber: giftNum,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (action instanceof GramJs.MessageActionStarGiftUnique) {
|
if (action instanceof GramJs.MessageActionStarGiftUnique) {
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import type {
|
|||||||
ApiVoice,
|
ApiVoice,
|
||||||
ApiWebDocument,
|
ApiWebDocument,
|
||||||
ApiWebPage,
|
ApiWebPage,
|
||||||
|
ApiWebPageAuctionData,
|
||||||
ApiWebPageStickerData,
|
ApiWebPageStickerData,
|
||||||
ApiWebPageStoryData,
|
ApiWebPageStoryData,
|
||||||
BoughtPaidMedia,
|
BoughtPaidMedia,
|
||||||
@ -863,11 +864,16 @@ export function buildWebPage(webPage: GramJs.TypeWebPage): ApiWebPage | undefine
|
|||||||
}
|
}
|
||||||
let story: ApiWebPageStoryData | undefined;
|
let story: ApiWebPageStoryData | undefined;
|
||||||
let gift: ApiStarGiftUnique | undefined;
|
let gift: ApiStarGiftUnique | undefined;
|
||||||
|
let auction: ApiWebPageAuctionData | undefined;
|
||||||
let stickers: ApiWebPageStickerData | undefined;
|
let stickers: ApiWebPageStickerData | undefined;
|
||||||
const attributeStory = attributes
|
const attributeStory = attributes
|
||||||
?.find((a): a is GramJs.WebPageAttributeStory => a instanceof GramJs.WebPageAttributeStory);
|
?.find((a): a is GramJs.WebPageAttributeStory => a instanceof GramJs.WebPageAttributeStory);
|
||||||
const attributeGift = attributes
|
const attributeGift = attributes
|
||||||
?.find((a): a is GramJs.WebPageAttributeUniqueStarGift => a instanceof GramJs.WebPageAttributeUniqueStarGift);
|
?.find((a): a is GramJs.WebPageAttributeUniqueStarGift => a instanceof GramJs.WebPageAttributeUniqueStarGift);
|
||||||
|
const attributeAuction = attributes
|
||||||
|
?.find((a): a is GramJs.WebPageAttributeStarGiftAuction => (
|
||||||
|
a instanceof GramJs.WebPageAttributeStarGiftAuction
|
||||||
|
));
|
||||||
if (attributeStory) {
|
if (attributeStory) {
|
||||||
const peerId = getApiChatIdFromMtpPeer(attributeStory.peer);
|
const peerId = getApiChatIdFromMtpPeer(attributeStory.peer);
|
||||||
story = {
|
story = {
|
||||||
@ -883,6 +889,15 @@ export function buildWebPage(webPage: GramJs.TypeWebPage): ApiWebPage | undefine
|
|||||||
const starGift = buildApiStarGift(attributeGift.gift);
|
const starGift = buildApiStarGift(attributeGift.gift);
|
||||||
gift = starGift.type === 'starGiftUnique' ? starGift : undefined;
|
gift = starGift.type === 'starGiftUnique' ? starGift : undefined;
|
||||||
}
|
}
|
||||||
|
if (attributeAuction) {
|
||||||
|
const starGift = buildApiStarGift(attributeAuction.gift);
|
||||||
|
if (starGift.type === 'starGift') {
|
||||||
|
auction = {
|
||||||
|
gift: starGift,
|
||||||
|
endDate: attributeAuction.endDate,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
const attributeStickers = attributes?.find((a): a is GramJs.WebPageAttributeStickerSet => (
|
const attributeStickers = attributes?.find((a): a is GramJs.WebPageAttributeStickerSet => (
|
||||||
a instanceof GramJs.WebPageAttributeStickerSet
|
a instanceof GramJs.WebPageAttributeStickerSet
|
||||||
));
|
));
|
||||||
@ -914,6 +929,7 @@ export function buildWebPage(webPage: GramJs.TypeWebPage): ApiWebPage | undefine
|
|||||||
audio,
|
audio,
|
||||||
story,
|
story,
|
||||||
gift,
|
gift,
|
||||||
|
auction,
|
||||||
stickers,
|
stickers,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -553,7 +553,7 @@ export function buildApiStarsTransaction(transaction: GramJs.StarsTransaction):
|
|||||||
const {
|
const {
|
||||||
date, id, peer, amount, description, photo, title, refund, extendedMedia, failed, msgId, pending, gift, reaction,
|
date, id, peer, amount, description, photo, title, refund, extendedMedia, failed, msgId, pending, gift, reaction,
|
||||||
subscriptionPeriod, stargift, giveawayPostId, starrefCommissionPermille, stargiftUpgrade, paidMessages,
|
subscriptionPeriod, stargift, giveawayPostId, starrefCommissionPermille, stargiftUpgrade, paidMessages,
|
||||||
stargiftResale, postsSearch, stargiftPrepaidUpgrade, stargiftDropOriginalDetails,
|
stargiftResale, postsSearch, stargiftPrepaidUpgrade, stargiftDropOriginalDetails, stargiftAuctionBid,
|
||||||
} = transaction;
|
} = transaction;
|
||||||
|
|
||||||
if (photo) {
|
if (photo) {
|
||||||
@ -595,6 +595,7 @@ export function buildApiStarsTransaction(transaction: GramJs.StarsTransaction):
|
|||||||
isPostsSearch: postsSearch,
|
isPostsSearch: postsSearch,
|
||||||
isDropOriginalDetails: stargiftDropOriginalDetails,
|
isDropOriginalDetails: stargiftDropOriginalDetails,
|
||||||
isPrepaidUpgrade: stargiftPrepaidUpgrade,
|
isPrepaidUpgrade: stargiftPrepaidUpgrade,
|
||||||
|
isStarGiftAuctionBid: stargiftAuctionBid,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -798,6 +798,20 @@ export function buildInputInvoice(invoice: ApiRequestInputInvoice) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'stargiftAuctionBid': {
|
||||||
|
const {
|
||||||
|
giftId, bidAmount, peer, message, shouldHideName, isUpdateBid,
|
||||||
|
} = invoice;
|
||||||
|
return new GramJs.InputInvoiceStarGiftAuctionBid({
|
||||||
|
giftId: BigInt(giftId),
|
||||||
|
bidAmount: BigInt(bidAmount),
|
||||||
|
peer: peer && buildInputPeer(peer.id, peer.accessHash || ''),
|
||||||
|
message: message && buildInputTextWithEntities(message),
|
||||||
|
hideName: shouldHideName || undefined,
|
||||||
|
updateBid: isUpdateBid || undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
case 'giveaway':
|
case 'giveaway':
|
||||||
default: {
|
default: {
|
||||||
const purpose = buildInputStorePaymentPurpose(invoice.purpose);
|
const purpose = buildInputStorePaymentPurpose(invoice.purpose);
|
||||||
|
|||||||
@ -18,6 +18,8 @@ import {
|
|||||||
buildApiResaleGifts,
|
buildApiResaleGifts,
|
||||||
buildApiSavedStarGift,
|
buildApiSavedStarGift,
|
||||||
buildApiStarGift,
|
buildApiStarGift,
|
||||||
|
buildApiStarGiftAuctionAcquiredGift,
|
||||||
|
buildApiStarGiftAuctionState,
|
||||||
buildApiStarGiftCollection,
|
buildApiStarGiftCollection,
|
||||||
buildApiStarGiftUpgradePreview,
|
buildApiStarGiftUpgradePreview,
|
||||||
buildInputResaleGiftsAttributes,
|
buildInputResaleGiftsAttributes,
|
||||||
@ -412,6 +414,51 @@ export async function fetchStarGiftUpgradePreview({
|
|||||||
return buildApiStarGiftUpgradePreview(result);
|
return buildApiStarGiftUpgradePreview(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function fetchStarGiftAuctionState({
|
||||||
|
giftId,
|
||||||
|
slug,
|
||||||
|
version = 0,
|
||||||
|
}: {
|
||||||
|
giftId?: string;
|
||||||
|
slug?: string;
|
||||||
|
version?: number;
|
||||||
|
}) {
|
||||||
|
if (!giftId && !slug) return undefined;
|
||||||
|
|
||||||
|
const auction = slug
|
||||||
|
? new GramJs.InputStarGiftAuctionSlug({ slug })
|
||||||
|
: new GramJs.InputStarGiftAuction({ giftId: BigInt(giftId!) });
|
||||||
|
|
||||||
|
const result = await invokeRequest(new GramJs.payments.GetStarGiftAuctionState({
|
||||||
|
auction,
|
||||||
|
version,
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buildApiStarGiftAuctionState(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchStarGiftAuctionAcquiredGifts({
|
||||||
|
giftId,
|
||||||
|
}: {
|
||||||
|
giftId: string;
|
||||||
|
}) {
|
||||||
|
const result = await invokeRequest(new GramJs.payments.GetStarGiftAuctionAcquiredGifts({
|
||||||
|
giftId: BigInt(giftId),
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
gifts: result.gifts.map(buildApiStarGiftAuctionAcquiredGift),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function upgradeStarGift({
|
export function upgradeStarGift({
|
||||||
inputSavedGift,
|
inputSavedGift,
|
||||||
shouldKeepOriginalDetails,
|
shouldKeepOriginalDetails,
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import {
|
|||||||
buildApiFormattedText,
|
buildApiFormattedText,
|
||||||
buildApiPhoto, buildApiUsernames, buildPrivacyRules,
|
buildApiPhoto, buildApiUsernames, buildPrivacyRules,
|
||||||
} from '../apiBuilders/common';
|
} from '../apiBuilders/common';
|
||||||
|
import { buildApiStarGiftAuctionUserState, buildApiTypeStarGiftAuctionState } from '../apiBuilders/gifts';
|
||||||
import { omitVirtualClassFields } from '../apiBuilders/helpers';
|
import { omitVirtualClassFields } from '../apiBuilders/helpers';
|
||||||
import {
|
import {
|
||||||
buildApiMessageExtendedMediaPreview,
|
buildApiMessageExtendedMediaPreview,
|
||||||
@ -1095,6 +1096,22 @@ export function updater(update: Update) {
|
|||||||
'@type': 'updateStarsBalance',
|
'@type': 'updateStarsBalance',
|
||||||
balance,
|
balance,
|
||||||
});
|
});
|
||||||
|
} else if (update instanceof GramJs.UpdateStarGiftAuctionState) {
|
||||||
|
const state = buildApiTypeStarGiftAuctionState(update.state);
|
||||||
|
if (!state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendApiUpdate({
|
||||||
|
'@type': 'updateStarGiftAuctionState',
|
||||||
|
giftId: update.giftId.toString(),
|
||||||
|
state,
|
||||||
|
});
|
||||||
|
} else if (update instanceof GramJs.UpdateStarGiftAuctionUserState) {
|
||||||
|
sendApiUpdate({
|
||||||
|
'@type': 'updateStarGiftAuctionUserState',
|
||||||
|
giftId: update.giftId.toString(),
|
||||||
|
userState: buildApiStarGiftAuctionUserState(update.userState),
|
||||||
|
});
|
||||||
} else if (update instanceof GramJs.UpdatePaidReactionPrivacy) {
|
} else if (update instanceof GramJs.UpdatePaidReactionPrivacy) {
|
||||||
sendApiUpdate({
|
sendApiUpdate({
|
||||||
'@type': 'updatePaidReactionPrivacy',
|
'@type': 'updatePaidReactionPrivacy',
|
||||||
|
|||||||
@ -243,6 +243,7 @@ export interface ApiMessageActionStarGift extends ActionMediaType {
|
|||||||
isRefunded?: true;
|
isRefunded?: true;
|
||||||
canUpgrade?: true;
|
canUpgrade?: true;
|
||||||
isPrepaidUpgrade?: true;
|
isPrepaidUpgrade?: true;
|
||||||
|
isAuctionAcquired?: true;
|
||||||
gift: ApiStarGiftRegular;
|
gift: ApiStarGiftRegular;
|
||||||
message?: ApiFormattedText;
|
message?: ApiFormattedText;
|
||||||
starsToConvert?: number;
|
starsToConvert?: number;
|
||||||
@ -253,6 +254,8 @@ export interface ApiMessageActionStarGift extends ActionMediaType {
|
|||||||
peerId?: string;
|
peerId?: string;
|
||||||
savedId?: string;
|
savedId?: string;
|
||||||
prepaidUpgradeHash?: string;
|
prepaidUpgradeHash?: string;
|
||||||
|
toId?: string;
|
||||||
|
giftNumber?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApiMessageActionStarGiftUnique extends ActionMediaType {
|
export interface ApiMessageActionStarGiftUnique extends ActionMediaType {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import type {
|
|||||||
ApiLabeledPrice,
|
ApiLabeledPrice,
|
||||||
} from './payments';
|
} from './payments';
|
||||||
import type { ApiTypePeerColor } from './peers';
|
import type { ApiTypePeerColor } from './peers';
|
||||||
import type { ApiStarGiftUnique, ApiTypeCurrencyAmount } from './stars';
|
import type { ApiStarGiftRegular, ApiStarGiftUnique, ApiTypeCurrencyAmount } from './stars';
|
||||||
import type {
|
import type {
|
||||||
ApiMessageStoryData, ApiStory, ApiWebPageStickerData, ApiWebPageStoryData,
|
ApiMessageStoryData, ApiStory, ApiWebPageStickerData, ApiWebPageStoryData,
|
||||||
} from './stories';
|
} from './stories';
|
||||||
@ -394,10 +394,16 @@ export interface ApiWebPageFull {
|
|||||||
video?: ApiVideo;
|
video?: ApiVideo;
|
||||||
story?: ApiWebPageStoryData;
|
story?: ApiWebPageStoryData;
|
||||||
gift?: ApiStarGiftUnique;
|
gift?: ApiStarGiftUnique;
|
||||||
|
auction?: ApiWebPageAuctionData;
|
||||||
stickers?: ApiWebPageStickerData;
|
stickers?: ApiWebPageStickerData;
|
||||||
hasLargeMedia?: boolean;
|
hasLargeMedia?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ApiWebPageAuctionData = {
|
||||||
|
gift: ApiStarGiftRegular;
|
||||||
|
endDate: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type ApiWebPage = ApiWebPagePending | ApiWebPageEmpty | ApiWebPageFull;
|
export type ApiWebPage = ApiWebPagePending | ApiWebPageEmpty | ApiWebPageFull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -412,11 +412,22 @@ export type ApiInputInvoiceStarGiftPrepaidUpgrade = {
|
|||||||
hash: string;
|
hash: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ApiInputInvoiceStarGiftAuctionBid = {
|
||||||
|
type: 'stargiftAuctionBid';
|
||||||
|
giftId: string;
|
||||||
|
bidAmount: number;
|
||||||
|
peerId?: string;
|
||||||
|
message?: ApiFormattedText;
|
||||||
|
shouldHideName?: boolean;
|
||||||
|
isUpdateBid?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type ApiInputInvoice = ApiInputInvoiceMessage | ApiInputInvoiceSlug | ApiInputInvoiceGiveaway
|
export type ApiInputInvoice = ApiInputInvoiceMessage | ApiInputInvoiceSlug | ApiInputInvoiceGiveaway
|
||||||
| ApiInputInvoiceGiftCode | ApiInputInvoicePremiumGiftStars | ApiInputInvoiceStars | ApiInputInvoiceStarsGift
|
| ApiInputInvoiceGiftCode | ApiInputInvoicePremiumGiftStars | ApiInputInvoiceStars | ApiInputInvoiceStarsGift
|
||||||
| ApiInputInvoiceStarsGiveaway | ApiInputInvoiceStarGift | ApiInputInvoiceChatInviteSubscription
|
| ApiInputInvoiceStarsGiveaway | ApiInputInvoiceStarGift | ApiInputInvoiceChatInviteSubscription
|
||||||
| ApiInputInvoiceStarGiftUpgrade | ApiInputInvoiceStarGiftTransfer | ApiInputInvoiceStarGiftResale
|
| ApiInputInvoiceStarGiftUpgrade | ApiInputInvoiceStarGiftTransfer | ApiInputInvoiceStarGiftResale
|
||||||
| ApiInputInvoiceStarGiftDropOriginalDetails | ApiInputInvoiceStarGiftPrepaidUpgrade;
|
| ApiInputInvoiceStarGiftDropOriginalDetails | ApiInputInvoiceStarGiftPrepaidUpgrade
|
||||||
|
| ApiInputInvoiceStarGiftAuctionBid;
|
||||||
|
|
||||||
/* Used for Invoice request */
|
/* Used for Invoice request */
|
||||||
export type ApiRequestInputInvoiceMessage = {
|
export type ApiRequestInputInvoiceMessage = {
|
||||||
@ -497,12 +508,23 @@ export type ApiRequestInputInvoiceStarGiftPrepaidUpgrade = {
|
|||||||
hash: string;
|
hash: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ApiRequestInputInvoiceStarGiftAuctionBid = {
|
||||||
|
type: 'stargiftAuctionBid';
|
||||||
|
giftId: string;
|
||||||
|
bidAmount: number;
|
||||||
|
peer?: ApiPeer;
|
||||||
|
message?: ApiFormattedText;
|
||||||
|
shouldHideName?: boolean;
|
||||||
|
isUpdateBid?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type ApiRequestInputInvoice = ApiRequestInputInvoiceMessage | ApiRequestInputInvoiceSlug
|
export type ApiRequestInputInvoice = ApiRequestInputInvoiceMessage | ApiRequestInputInvoiceSlug
|
||||||
| ApiRequestInputInvoiceGiveaway | ApiRequestInputInvoiceStars | ApiRequestInputInvoiceStarsGiveaway
|
| ApiRequestInputInvoiceGiveaway | ApiRequestInputInvoiceStars | ApiRequestInputInvoiceStarsGiveaway
|
||||||
| ApiRequestInputInvoiceChatInviteSubscription | ApiRequestInputInvoiceStarGift
|
| ApiRequestInputInvoiceChatInviteSubscription | ApiRequestInputInvoiceStarGift
|
||||||
| ApiRequestInputInvoiceStarGiftUpgrade | ApiRequestInputInvoiceStarGiftTransfer
|
| ApiRequestInputInvoiceStarGiftUpgrade | ApiRequestInputInvoiceStarGiftTransfer
|
||||||
| ApiRequestInputInvoicePremiumGiftStars | ApiRequestInputInvoiceStarGiftResale
|
| ApiRequestInputInvoicePremiumGiftStars | ApiRequestInputInvoiceStarGiftResale
|
||||||
| ApiRequestInputInvoiceStarGiftDropOriginalDetails | ApiRequestInputInvoiceStarGiftPrepaidUpgrade;
|
| ApiRequestInputInvoiceStarGiftDropOriginalDetails | ApiRequestInputInvoiceStarGiftPrepaidUpgrade
|
||||||
|
| ApiRequestInputInvoiceStarGiftAuctionBid;
|
||||||
|
|
||||||
export interface ApiUniqueStarGiftValueInfo {
|
export interface ApiUniqueStarGiftValueInfo {
|
||||||
isLastSaleOnFragment?: true;
|
isLastSaleOnFragment?: true;
|
||||||
|
|||||||
@ -27,6 +27,15 @@ export interface ApiStarGiftRegular {
|
|||||||
perUserTotal?: number;
|
perUserTotal?: number;
|
||||||
perUserRemains?: number;
|
perUserRemains?: number;
|
||||||
lockedUntilDate?: number;
|
lockedUntilDate?: number;
|
||||||
|
isAuction?: true;
|
||||||
|
giftsPerRound?: number;
|
||||||
|
background?: ApiStarGiftBackground;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApiStarGiftBackground {
|
||||||
|
centerColor: string;
|
||||||
|
edgeColor: string;
|
||||||
|
textColor: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApiStarGiftUnique {
|
export interface ApiStarGiftUnique {
|
||||||
@ -103,6 +112,7 @@ export interface ApiStarGiftUpgradePreview {
|
|||||||
export interface ApiSavedStarGift {
|
export interface ApiSavedStarGift {
|
||||||
isNameHidden?: boolean;
|
isNameHidden?: boolean;
|
||||||
isUnsaved?: boolean;
|
isUnsaved?: boolean;
|
||||||
|
isRefunded?: boolean;
|
||||||
fromId?: string;
|
fromId?: string;
|
||||||
date: number;
|
date: number;
|
||||||
gift: ApiStarGift;
|
gift: ApiStarGift;
|
||||||
@ -259,6 +269,7 @@ export interface ApiStarsTransaction {
|
|||||||
isPostsSearch?: true;
|
isPostsSearch?: true;
|
||||||
isDropOriginalDetails?: true;
|
isDropOriginalDetails?: true;
|
||||||
isPrepaidUpgrade?: true;
|
isPrepaidUpgrade?: true;
|
||||||
|
isStarGiftAuctionBid?: true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApiStarsSubscription {
|
export interface ApiStarsSubscription {
|
||||||
@ -315,3 +326,63 @@ export interface ApiStarsRating {
|
|||||||
stars: number;
|
stars: number;
|
||||||
nextLevelStars?: number;
|
nextLevelStars?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ApiAuctionBidLevel {
|
||||||
|
pos: number;
|
||||||
|
amount: number;
|
||||||
|
date: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApiStarGiftAuctionStateActive {
|
||||||
|
type: 'active';
|
||||||
|
version: number;
|
||||||
|
startDate: number;
|
||||||
|
endDate: number;
|
||||||
|
minBidAmount: number;
|
||||||
|
bidLevels: ApiAuctionBidLevel[];
|
||||||
|
topBidders: string[];
|
||||||
|
nextRoundAt: number;
|
||||||
|
lastGiftNum: number;
|
||||||
|
giftsLeft: number;
|
||||||
|
currentRound: number;
|
||||||
|
totalRounds: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApiStarGiftAuctionStateFinished {
|
||||||
|
type: 'finished';
|
||||||
|
startDate: number;
|
||||||
|
endDate: number;
|
||||||
|
averagePrice: number;
|
||||||
|
listedCount?: number;
|
||||||
|
fragmentListedCount?: number;
|
||||||
|
fragmentListedUrl?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApiStarGiftAuctionUserState {
|
||||||
|
isReturned?: true;
|
||||||
|
bidAmount?: number;
|
||||||
|
bidDate?: number;
|
||||||
|
minBidAmount?: number;
|
||||||
|
bidPeerId?: string;
|
||||||
|
acquiredCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ApiTypeStarGiftAuctionState = ApiStarGiftAuctionStateActive | ApiStarGiftAuctionStateFinished;
|
||||||
|
|
||||||
|
export interface ApiStarGiftAuctionState {
|
||||||
|
gift: ApiStarGiftRegular;
|
||||||
|
state: ApiTypeStarGiftAuctionState;
|
||||||
|
userState: ApiStarGiftAuctionUserState;
|
||||||
|
timeout: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApiStarGiftAuctionAcquiredGift {
|
||||||
|
peerId: string;
|
||||||
|
date: number;
|
||||||
|
bidAmount: number;
|
||||||
|
round: number;
|
||||||
|
position: number;
|
||||||
|
message?: ApiFormattedText;
|
||||||
|
giftNumber?: number;
|
||||||
|
isNameHidden?: true;
|
||||||
|
}
|
||||||
|
|||||||
@ -45,7 +45,7 @@ import type {
|
|||||||
} from './misc';
|
} from './misc';
|
||||||
import type { ApiEmojiStatusType, ApiPeerSettings } from './peers';
|
import type { ApiEmojiStatusType, ApiPeerSettings } from './peers';
|
||||||
import type { ApiPrivacyKey, LangPackStringValue, PrivacyVisibility } from './settings';
|
import type { ApiPrivacyKey, LangPackStringValue, PrivacyVisibility } from './settings';
|
||||||
import type { ApiTypeCurrencyAmount } from './stars';
|
import type { ApiStarGiftAuctionUserState, ApiTypeCurrencyAmount, ApiTypeStarGiftAuctionState } from './stars';
|
||||||
import type { ApiStealthMode, ApiStory, ApiStorySkipped } from './stories';
|
import type { ApiStealthMode, ApiStory, ApiStorySkipped } from './stories';
|
||||||
import type {
|
import type {
|
||||||
ApiUser, ApiUserFullInfo, ApiUserStatus,
|
ApiUser, ApiUserFullInfo, ApiUserStatus,
|
||||||
@ -834,6 +834,18 @@ export type ApiUpdateStarsBalance = {
|
|||||||
balance: ApiTypeCurrencyAmount;
|
balance: ApiTypeCurrencyAmount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ApiUpdateStarGiftAuctionState = {
|
||||||
|
'@type': 'updateStarGiftAuctionState';
|
||||||
|
giftId: string;
|
||||||
|
state: ApiTypeStarGiftAuctionState;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ApiUpdateStarGiftAuctionUserState = {
|
||||||
|
'@type': 'updateStarGiftAuctionUserState';
|
||||||
|
giftId: string;
|
||||||
|
userState: ApiStarGiftAuctionUserState;
|
||||||
|
};
|
||||||
|
|
||||||
export type ApiUpdateDeleteProfilePhoto = {
|
export type ApiUpdateDeleteProfilePhoto = {
|
||||||
'@type': 'updateDeleteProfilePhoto';
|
'@type': 'updateDeleteProfilePhoto';
|
||||||
peerId: string;
|
peerId: string;
|
||||||
@ -915,10 +927,11 @@ export type ApiUpdate = (
|
|||||||
ApiRequestReconnectApi | ApiRequestSync | ApiUpdateFetchingDifference | ApiUpdateChannelMessages |
|
ApiRequestReconnectApi | ApiRequestSync | ApiUpdateFetchingDifference | ApiUpdateChannelMessages |
|
||||||
ApiUpdateStealthMode | ApiUpdateAttachMenuBots | ApiUpdateNewAuthorization | ApiUpdateGroupInvitePrivacyForbidden |
|
ApiUpdateStealthMode | ApiUpdateAttachMenuBots | ApiUpdateNewAuthorization | ApiUpdateGroupInvitePrivacyForbidden |
|
||||||
ApiUpdateViewForumAsMessages | ApiUpdateSavedDialogPinned | ApiUpdatePinnedSavedDialogIds | ApiUpdateChatLastMessage |
|
ApiUpdateViewForumAsMessages | ApiUpdateSavedDialogPinned | ApiUpdatePinnedSavedDialogIds | ApiUpdateChatLastMessage |
|
||||||
ApiUpdateDeleteSavedHistory | ApiUpdatePremiumFloodWait | ApiUpdateStarsBalance | ApiUpdateBotCommands |
|
ApiUpdateDeleteSavedHistory | ApiUpdatePremiumFloodWait | ApiUpdateStarsBalance | ApiUpdateStarGiftAuctionState
|
||||||
ApiUpdateQuickReplyMessage | ApiUpdateQuickReplies | ApiDeleteQuickReply | ApiUpdateDeleteQuickReplyMessages |
|
| ApiUpdateStarGiftAuctionUserState | ApiUpdateBotCommands | ApiUpdateQuickReplyMessage | ApiUpdateQuickReplies
|
||||||
ApiUpdateDeleteProfilePhoto | ApiUpdateNewProfilePhoto | ApiUpdateEntities | ApiUpdatePaidReactionPrivacy |
|
| ApiDeleteQuickReply | ApiUpdateDeleteQuickReplyMessages | ApiUpdateDeleteProfilePhoto | ApiUpdateNewProfilePhoto
|
||||||
ApiUpdateLangPackTooLong | ApiUpdateLangPack | ApiUpdateNotSupportedInFrozenAccountError
|
| ApiUpdateEntities | ApiUpdatePaidReactionPrivacy | ApiUpdateLangPackTooLong | ApiUpdateLangPack
|
||||||
|
| ApiUpdateNotSupportedInFrozenAccountError
|
||||||
);
|
);
|
||||||
|
|
||||||
export type OnApiUpdate = (update: ApiUpdate) => void;
|
export type OnApiUpdate = (update: ApiUpdate) => void;
|
||||||
|
|||||||
1
src/assets/font-icons/auction-drop.svg
Normal file
1
src/assets/font-icons/auction-drop.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M29.556 13.557C29.556 6.082 23.474 0 16 0S2.444 6.082 2.444 13.557v.543l9.13 6.917a3.67 3.67 0 0 0-1.453 2.911v4.387A3.69 3.69 0 0 0 13.806 32h4.387a3.69 3.69 0 0 0 3.685-3.685v-4.387a3.67 3.67 0 0 0-1.453-2.91l9.131-6.918zm-18.558.848 1.859 4.842-7.25-5.493c.06-.035.127-.071.183-.105.492-.3.818-.498 1.591-.498s1.099.198 1.59.498c.486.294 1.086.634 2.027.756m4.583 5.839-2.314-6.03a5.7 5.7 0 0 0 1.154-.567c.492-.298.816-.496 1.587-.496s1.095.198 1.587.496a5.7 5.7 0 0 0 1.157.57l-2.313 6.027zm5.44-5.84c.938-.122 1.536-.462 2.018-.757.492-.298.816-.496 1.587-.496s1.094.198 1.585.496c.056.035.123.071.182.106l-7.221 5.472zM16 2.187c5.637 0 10.32 4.126 11.21 9.514-.574-.347-1.299-.735-2.583-.735-1.384 0-2.127.453-2.724.816-.49.299-.814.496-1.585.496s-1.094-.197-1.585-.496c-.597-.363-1.34-.816-2.724-.816s-2.126.453-2.723.816c-.492.299-.816.496-1.587.496-.773 0-1.098-.197-1.59-.497-.598-.363-1.341-.815-2.727-.815-1.288 0-2.014.39-2.591.737.89-5.39 5.573-9.516 11.21-9.516m3.693 26.13a1.5 1.5 0 0 1-1.5 1.498h-4.386a1.5 1.5 0 0 1-1.499-1.499v-4.387a1.5 1.5 0 0 1 1.499-1.498h4.387a1.5 1.5 0 0 1 1.499 1.498z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
1
src/assets/font-icons/auction-filled.svg
Normal file
1
src/assets/font-icons/auction-filled.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 32 32"><path d="m23.632 12.635-6.73 6.73a.697.697 0 0 1-.986 0l-6.149-6.15a.697.697 0 0 1 0-.986l6.73-6.73a.697.697 0 0 1 .986 0l6.149 6.15a.697.697 0 0 1 0 .986M28.447 11.533a2.34 2.34 0 0 1-3.307 0L17.6 3.992A2.338 2.338 0 1 1 20.906.685l7.54 7.541a2.34 2.34 0 0 1 0 3.307M31.159 26.892a2.87 2.87 0 0 1-4.06 0l-7.528-7.527a.697.697 0 0 1 0-.987l3.075-3.074a.697.697 0 0 1 .986 0l7.527 7.527a2.87 2.87 0 0 1 0 4.06M15.771 24.209a2.34 2.34 0 0 1-3.306 0l-7.542-7.542A2.338 2.338 0 1 1 8.23 13.36l7.541 7.542a2.34 2.34 0 0 1 0 3.307M18.896 29.805v1.498A.697.697 0 0 1 18.2 32H.697A.697.697 0 0 1 0 31.303v-1.498c0-1.37 1.11-2.481 2.481-2.481h13.934c1.37 0 2.481 1.11 2.481 2.48"/></svg>
|
||||||
|
After Width: | Height: | Size: 750 B |
1
src/assets/font-icons/auction-next-round.svg
Normal file
1
src/assets/font-icons/auction-next-round.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 32 32"><path d="M20.989 22.53q-.163 0-.322-.02a2.53 2.53 0 0 1-1.641-.914l-.954-1.171-1.468.258a2.52 2.52 0 0 1-2.919-1.952 2.5 2.5 0 0 1 .4-1.963l.73-1.033.028-.04a4 4 0 0 1-.194-.291l-.526-.885a2.52 2.52 0 0 1-.264-1.946 2.47 2.47 0 0 1 1.217-1.529l.182-.087a2.56 2.56 0 0 1 1.727-.115l1.43.413.972-1.013c.933-.975 2.511-1.029 3.52-.117a2.52 2.52 0 0 1 .829 1.735l.072 1.403 1.366.629c.61.28 1.09.803 1.322 1.433a2.47 2.47 0 0 1-.085 1.909 2.5 2.5 0 0 1-1.457 1.304l-1.32.45-.145 1.323a2.47 2.47 0 0 1-.934 1.681 2.55 2.55 0 0 1-1.566.539m-2.083-4.347 1.72 2.11a.48.48 0 0 0 .306.172c.13.012.252-.02.35-.097a.4.4 0 0 0 .156-.285l.291-2.625 2.56-.872a.44.44 0 0 0 .253-.225.4.4 0 0 0 .017-.327.48.48 0 0 0-.247-.269l-2.5-1.15-.137-2.649a.45.45 0 0 0-.148-.31c-.168-.15-.46-.187-.649.012l-1.836 1.916-2.631-.76a.47.47 0 0 0-.311.015l-.089.044c-.088.049-.142.159-.164.238a.44.44 0 0 0 .048.343l.526.882c.12.204.284.38.482.526l1.175.862-1.203.822q-.221.151-.375.37l-.73 1.032a.43.43 0 0 0-.068.337c.058.268.327.39.544.357z" class="st3"/><path d="M20.139 27.861c-6.54 0-11.862-5.321-11.862-11.861S13.6 4.139 20.14 4.139 32 9.46 32 16s-5.321 11.861-11.861 11.861m0-21.66c-5.403 0-9.799 4.396-9.799 9.799s4.396 9.798 9.799 9.798 9.798-4.395 9.798-9.798-4.395-9.798-9.798-9.798M8.169 9.296H2.797a.604.604 0 0 1-.604-.605v-.854c0-.333.27-.604.604-.604H8.17c.333 0 .604.27.604.604v.854c0 .334-.27.605-.604.605M8.169 24.767H2.797a.604.604 0 0 1-.604-.604v-.854c0-.334.27-.605.604-.605H8.17c.333 0 .604.27.604.605v.854c0 .333-.27.604-.604.604M5.975 17.031H.605A.604.604 0 0 1 0 16.427v-.854c0-.334.27-.604.604-.604h5.37c.335 0 .605.27.605.604v.854c0 .334-.27.604-.604.604"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
@ -1 +1 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" x="0" y="0" version="1.1" viewBox="0 0 32 32"><style>.st3{fill:#4e8ee5}</style><path d="M11.1 18c-7.4 0-10 4.3-10.9 6.8-.4 1-.2 2.1.4 2.9.7 1 1.9 1.6 3.1 1.6h14.8c1.3 0 2.4-.6 3.1-1.6.6-.9.7-1.9.4-2.9-.9-2.5-3.5-6.8-10.9-6.8m8.6 8.4c-.2.3-.7.5-1.2.5H3.7c-.5 0-1-.2-1.2-.5-.2-.2-.2-.5-.1-.8.9-2.4 3.1-5.2 8.7-5.2s7.8 2.8 8.7 5.2c.1.3.1.5-.1.8M31.8 23.9c-.8-2.3-3-6.1-9.6-6.1h-.8c-.7 0-1.2.6-1.1 1.2 0 .7.6 1.2 1.2 1.1h.7c4.8 0 6.6 2.4 7.3 4.5.1.2 0 .3-.1.4-.1.2-.4.3-.8.3h-4.3c-.7 0-1.2.5-1.2 1.2s.5 1.2 1.2 1.2h4.3c1.1 0 2.1-.5 2.7-1.3.7-.7.8-1.6.5-2.5M4.6 11.2l.9.7c.1.1.2.2.3.2v.1l-.4 1.4c-.2.8-.1 1.6.4 2.3.8 1.3 2.6 1.7 3.9.9l1.5-.9 1.5.9c.5.3 1 .4 1.5.4.2 0 .4 0 .7-.1.8-.2 1.4-.7 1.8-1.3.4-.7.5-1.4.3-2.2l-.4-1.5.8-.6c.2.4.4.8.8 1l.4.3-.1.5c-.2.7-.1 1.5.3 2.1.8 1.2 2.4 1.6 3.7.9l.6-.3.6.4c.4.2.9.4 1.4.4.2 0 .4 0 .6-.1.7-.2 1.3-.6 1.7-1.2s.5-1.4.3-2.1l-.1-.5.4-.4c.6-.5.9-1.1 1-1.9.1-.7-.2-1.4-.6-2-.5-.6-1.2-.9-1.9-1l-.7-.1-.4-.8c-.3-.5-.8-1-1.4-1.2-1.3-.5-2.7 0-3.4 1.2l-.4.8h-.7c-.3 0-.6.1-.9.2-.1-.3-.3-.6-.5-.9-.5-.6-1.2-1-2-1l-1.6.2-.6-1.5c-.3-.7-.9-1.3-1.6-1.5-1.5-.7-3.2 0-3.8 1.5L7.9 6l-1.7.1c-.7 0-1.3.3-1.8.8l-.2.2c-.5.6-.8 1.3-.7 2.1s.5 1.5 1.1 2m14.9-.9c.1-.1.2-.2.3-.2l2.1-.2.8-1.9c.1-.2.3-.2.4-.1.2.1.2.1.3.1l.8 1.9 2.1.2c.1 0 .2.1.3.1.1.1.1.1.1.2s-.1.2-.1.2L25 11.9l.5 2v.2l-.2.2H25l-1.8-1.1-1.8 1c-.1.1-.4.1-.5-.1 0-.1-.1-.2 0-.3l.3-1.3.1-.1 2.1-1.2c.1-.1 0-.2-.1-.2l-2.5.1h-.1c-.1 0-.2-.1-.2-.2l-.6-.5c-.1-.1-.1-.2-.1-.2-.3.3-.3.2-.3.1M5.9 8.7c.2-.2.3-.2.4-.2l3.1-.2 1.2-2.8c.1-.3.5-.4.7-.3l.3.3 1.2 2.8 3.2.2c.1 0 .3.1.4.2s.1.2.1.4c0 .1-.1.3-.2.3l-2.4 2 .7 2.9c0 .1 0 .3-.1.4s-.2.2-.3.2-.3 0-.4-.1l-2.7-1.6-2.7 1.6c-.2.1-.6.1-.7-.2-.1-.1-.1-.3-.1-.4l.4-1.4c.1-.2.1-.4.3-.6l3.9-2c.1-.1.1-.3-.1-.2l-4.5.4c-.3-.1-.5-.2-.7-.4L6 9.3c-.1-.1-.1-.2-.1-.3z"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" x="0" y="0" version="1.1" viewBox="0 0 32 32"><path d="M11.1 18c-7.4 0-10 4.3-10.9 6.8-.4 1-.2 2.1.4 2.9.7 1 1.9 1.6 3.1 1.6h14.8c1.3 0 2.4-.6 3.1-1.6.6-.9.7-1.9.4-2.9-.9-2.5-3.5-6.8-10.9-6.8m8.6 8.4c-.2.3-.7.5-1.2.5H3.7c-.5 0-1-.2-1.2-.5-.2-.2-.2-.5-.1-.8.9-2.4 3.1-5.2 8.7-5.2s7.8 2.8 8.7 5.2c.1.3.1.5-.1.8M31.8 23.9c-.8-2.3-3-6.1-9.6-6.1h-.8c-.7 0-1.2.6-1.1 1.2 0 .7.6 1.2 1.2 1.1h.7c4.8 0 6.6 2.4 7.3 4.5.1.2 0 .3-.1.4-.1.2-.4.3-.8.3h-4.3c-.7 0-1.2.5-1.2 1.2s.5 1.2 1.2 1.2h4.3c1.1 0 2.1-.5 2.7-1.3.7-.7.8-1.6.5-2.5M4.6 11.2l.9.7c.1.1.2.2.3.2v.1l-.4 1.4c-.2.8-.1 1.6.4 2.3.8 1.3 2.6 1.7 3.9.9l1.5-.9 1.5.9c.5.3 1 .4 1.5.4.2 0 .4 0 .7-.1.8-.2 1.4-.7 1.8-1.3.4-.7.5-1.4.3-2.2l-.4-1.5.8-.6c.2.4.4.8.8 1l.4.3-.1.5c-.2.7-.1 1.5.3 2.1.8 1.2 2.4 1.6 3.7.9l.6-.3.6.4c.4.2.9.4 1.4.4.2 0 .4 0 .6-.1.7-.2 1.3-.6 1.7-1.2s.5-1.4.3-2.1l-.1-.5.4-.4c.6-.5.9-1.1 1-1.9.1-.7-.2-1.4-.6-2-.5-.6-1.2-.9-1.9-1l-.7-.1-.4-.8c-.3-.5-.8-1-1.4-1.2-1.3-.5-2.7 0-3.4 1.2l-.4.8h-.7c-.3 0-.6.1-.9.2-.1-.3-.3-.6-.5-.9-.5-.6-1.2-1-2-1l-1.6.2-.6-1.5c-.3-.7-.9-1.3-1.6-1.5-1.5-.7-3.2 0-3.8 1.5L7.9 6l-1.7.1c-.7 0-1.3.3-1.8.8l-.2.2c-.5.6-.8 1.3-.7 2.1s.5 1.5 1.1 2m14.9-.9c.1-.1.2-.2.3-.2l2.1-.2.8-1.9c.1-.2.3-.2.4-.1.2.1.2.1.3.1l.8 1.9 2.1.2c.1 0 .2.1.3.1.1.1.1.1.1.2s-.1.2-.1.2L25 11.9l.5 2v.2l-.2.2H25l-1.8-1.1-1.8 1c-.1.1-.4.1-.5-.1 0-.1-.1-.2 0-.3l.3-1.3.1-.1 2.1-1.2c.1-.1 0-.2-.1-.2l-2.5.1h-.1c-.1 0-.2-.1-.2-.2l-.6-.5c-.1-.1-.1-.2-.1-.2-.3.3-.3.2-.3.1M5.9 8.7c.2-.2.3-.2.4-.2l3.1-.2 1.2-2.8c.1-.3.5-.4.7-.3l.3.3 1.2 2.8 3.2.2c.1 0 .3.1.4.2s.1.2.1.4c0 .1-.1.3-.2.3l-2.4 2 .7 2.9c0 .1 0 .3-.1.4s-.2.2-.3.2-.3 0-.4-.1l-2.7-1.6-2.7 1.6c-.2.1-.6.1-.7-.2-.1-.1-.1-.3-.1-.4l.4-1.4c.1-.2.1-.4.3-.6l3.9-2c.1-.1.1-.3-.1-.2l-4.5.4c-.3-.1-.5-.2-.7-.4L6 9.3c-.1-.1-.1-.2-.1-.3z"/></svg>
|
||||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
@ -1513,6 +1513,7 @@
|
|||||||
"GiftInfoDescriptionUpgrade2" = "Upgrade this gift to turn it to a unique collectible.";
|
"GiftInfoDescriptionUpgrade2" = "Upgrade this gift to turn it to a unique collectible.";
|
||||||
"GiftInfoPeerDescriptionFreeUpgradeOut" = "{peer} can turn this gift into a unique collectible";
|
"GiftInfoPeerDescriptionFreeUpgradeOut" = "{peer} can turn this gift into a unique collectible";
|
||||||
"GiftInfoDescriptionUpgraded" = "This gift was turned into a unique collectible.";
|
"GiftInfoDescriptionUpgraded" = "This gift was turned into a unique collectible.";
|
||||||
|
"GiftInfoDescriptionRefunded" = "This gift was downgraded because a request to refund the payment related to this gift was made, and the money was returned.";
|
||||||
"GiftInfoFrom" = "From";
|
"GiftInfoFrom" = "From";
|
||||||
"GiftInfoDate" = "Date";
|
"GiftInfoDate" = "Date";
|
||||||
"GiftInfoValue" = "Value";
|
"GiftInfoValue" = "Value";
|
||||||
@ -1929,6 +1930,9 @@
|
|||||||
"ActionStarGiftUniqueBackdrop" = "Backdrop";
|
"ActionStarGiftUniqueBackdrop" = "Backdrop";
|
||||||
"ActionStarGiftUniqueSymbol" = "Symbol";
|
"ActionStarGiftUniqueSymbol" = "Symbol";
|
||||||
"ActionStarGiftSelf" = "Saved Gift";
|
"ActionStarGiftSelf" = "Saved Gift";
|
||||||
|
"ActionStarGiftAuctionWon" = "You won the auction with a bid of {cost}";
|
||||||
|
"ActionStarGiftAuctionFor" = "Gift for {peer}";
|
||||||
|
"ActionStarGiftAuctionBought" = "You bought this gift at auction for {cost}.";
|
||||||
"ActionSuggestedPhotoYou" = "You suggested this photo for {user}'s Telegram profile.";
|
"ActionSuggestedPhotoYou" = "You suggested this photo for {user}'s Telegram profile.";
|
||||||
"ActionSuggestedPhoto" = "{user} suggests this photo for your Telegram profile.";
|
"ActionSuggestedPhoto" = "{user} suggests this photo for your Telegram profile.";
|
||||||
"ActionSuggestedPhotoButton" = "View Photo";
|
"ActionSuggestedPhotoButton" = "View Photo";
|
||||||
@ -2343,6 +2347,8 @@
|
|||||||
"StarGiftReasonDropOriginalDetails" = "Removed Description";
|
"StarGiftReasonDropOriginalDetails" = "Removed Description";
|
||||||
"GiftAnUpgradeButton" = "Gift an Upgrade";
|
"GiftAnUpgradeButton" = "Gift an Upgrade";
|
||||||
"GiftPrepaidUpgradeTransactionTitle" = "Gift Upgrade";
|
"GiftPrepaidUpgradeTransactionTitle" = "Gift Upgrade";
|
||||||
|
"StarGiftAuctionBidTransaction" = "Auction Bid";
|
||||||
|
"StarGiftAuctionBidRefundedTransaction" = "Refunded Auction Bid";
|
||||||
"ActionStarGiftPrepaidUpgraded" = "{user} turned the gift into a unique collectible";
|
"ActionStarGiftPrepaidUpgraded" = "{user} turned the gift into a unique collectible";
|
||||||
"ActionStarGiftPrepaidUpgradedYou" = "You turned the gift into a unique collectible";
|
"ActionStarGiftPrepaidUpgradedYou" = "You turned the gift into a unique collectible";
|
||||||
"UserNoteTitle" = "Notes";
|
"UserNoteTitle" = "Notes";
|
||||||
@ -2405,6 +2411,66 @@
|
|||||||
"StarGiftUpgradeCostModalTitle" = "Upgrade Cost";
|
"StarGiftUpgradeCostModalTitle" = "Upgrade Cost";
|
||||||
"StarGiftUpgradeCostHint" = "Users who upgrade their gifts first get collectibles with lower numbers.";
|
"StarGiftUpgradeCostHint" = "Users who upgrade their gifts first get collectibles with lower numbers.";
|
||||||
"StarGiftPriceDecreaseTimer" = "Price decreases in {timer}";
|
"StarGiftPriceDecreaseTimer" = "Price decreases in {timer}";
|
||||||
|
"GiftRibbonAuction" = "auction";
|
||||||
|
"GiftAuctionJoin" = "Join";
|
||||||
|
"GiftAuctionLearnMore" = "Learn More >";
|
||||||
|
"GiftAuctionTopBidders_one" = "Top **{count}** bidder will get **{gift}** gift this round. {link}";
|
||||||
|
"GiftAuctionTopBidders_other" = "Top **{count}** bidders will get **{gift}** gifts this round. {link}";
|
||||||
|
"GiftAuctionStarted" = "Started";
|
||||||
|
"GiftAuctionEnds" = "Ends";
|
||||||
|
"GiftAuctionCurrentRound" = "Current Round";
|
||||||
|
"GiftAuctionRoundValue" = "{current} of {total}";
|
||||||
|
"GiftAuctionDescription_one" = "{count} gift is dropped at varying intervals to the top {count} bidder by bid amount. {link}";
|
||||||
|
"GiftAuctionDescription_other" = "{count} gifts are dropped at varying intervals to the top {count} bidders by bid amount. {link}";
|
||||||
|
"GiftAuctionPlaceBid" = "Place a Bid";
|
||||||
|
"GiftAuctionPlaceBidButton" = "Place a {amount} Bid";
|
||||||
|
"GiftAuctionMinimumBid" = "minimum bid";
|
||||||
|
"GiftAuctionUntilNextRound" = "until next round";
|
||||||
|
"GiftAuctionLeft" = "left";
|
||||||
|
"GiftAuctionTimeLeft" = "{time} left";
|
||||||
|
"GiftAuctionYourBidWillBe" = "Your bid will be";
|
||||||
|
"GiftAuctionYoureWinning" = "You're winning";
|
||||||
|
"GiftAuctionTopWinners_one" = "Top {count} Winner";
|
||||||
|
"GiftAuctionTopWinners_other" = "Top {count} Winners";
|
||||||
|
"GiftAuctionAddToBid" = "Add {amount} to Your Bid";
|
||||||
|
"GiftAuctionBalance" = "Balance";
|
||||||
|
"GiftAuctionInfoTitle" = "Auction";
|
||||||
|
"GiftAuctionInfoSubtitle" = "Join the battle for exclusive gifts.";
|
||||||
|
"GiftAuctionInfoTopBiddersTitle_one" = "Top {count} Bidder";
|
||||||
|
"GiftAuctionInfoTopBiddersTitle_other" = "Top {count} Bidders";
|
||||||
|
"GiftAuctionInfoTopBiddersSubtitle_one" = "{count} gift is dropped at varying intervals to the top {count} bidder by bid amount.";
|
||||||
|
"GiftAuctionInfoTopBiddersSubtitle_other" = "{count} gifts are dropped at varying intervals to the top {count} bidders by bid amount.";
|
||||||
|
"GiftAuctionInfoBidCarryoverTitle" = "Bid Carryover";
|
||||||
|
"GiftAuctionInfoBidCarryoverSubtitle" = "If your bid leaves the top {count}, it will automatically join the next round.";
|
||||||
|
"GiftAuctionInfoMissedBiddersTitle" = "Missed Bidders";
|
||||||
|
"GiftAuctionInfoMissedBiddersSubtitle" = "If your bid doesn't win after the final round, your Stars will be fully refunded.";
|
||||||
|
"GiftAuctionItemsBought_one" = "{count} {gift} item bought >";
|
||||||
|
"GiftAuctionItemsBought_other" = "{count} {gift} items bought >";
|
||||||
|
"GiftAuctionBoughtGiftsTitle_one" = "{count} Bought Gift";
|
||||||
|
"GiftAuctionBoughtGiftsTitle_other" = "{count} Bought Gifts";
|
||||||
|
"GiftAuctionBoughtGiftHeader" = "{gift} #{giftNumber} in round {round}";
|
||||||
|
"GiftAuctionRecipient" = "Recipient";
|
||||||
|
"GiftAuctionDate" = "Date";
|
||||||
|
"GiftAuctionAcceptedBid" = "Accepted Bid";
|
||||||
|
"GiftAuctionTopPosition" = "TOP {position}";
|
||||||
|
"GiftAuctionCustomBidTitle" = "Place a Custom Bid";
|
||||||
|
"GiftAuctionCustomBidDescription" = "If you fall below the top {count}, your bid will roll over to the next round.";
|
||||||
|
"GiftAuctionCustomBidPlaceholder" = "Custom Bid...";
|
||||||
|
"GiftAuctionCustomBidButton" = "Place a Bid";
|
||||||
|
"GiftAuctionBidPlacedTitle" = "Your bid has been placed";
|
||||||
|
"GiftAuctionBidIncreasedTitle" = "Your bid has been increased";
|
||||||
|
"GiftAuctionBidPlacedMessage" = "If you fall below the top {count}, your bid will roll over to the next round.";
|
||||||
|
"GiftAuctionFinished" = "Finished";
|
||||||
|
"GiftAuctionEnded" = "Auction ended";
|
||||||
|
"GiftAuctionSoldOut" = "Sold Out!";
|
||||||
|
"GiftAuctionGifts_one" = "{count} Gift";
|
||||||
|
"GiftAuctionGifts_other" = "{count} Gifts";
|
||||||
|
"GiftAuctionChangeRecipientTitle" = "Change Recipient";
|
||||||
|
"GiftAuctionChangeRecipientDescription" = "You've already placed a bid on this gift for **{oldPeer}**. Do you want to raise your bid and change the recipient to **{newPeer}**?";
|
||||||
|
"GiftAuctionAveragePrice" = "Average Price";
|
||||||
|
"GiftAuctionTapToBidMore" = "click to bid more";
|
||||||
|
"GiftAuctionWonNotification" = "You won {gift} at the auction!";
|
||||||
|
"StarGift" = "Star Gift";
|
||||||
"SettingsItemPrivacyPasskeys" = "Passkeys";
|
"SettingsItemPrivacyPasskeys" = "Passkeys";
|
||||||
"SettingsItemPrivacyOn" = "Enabled";
|
"SettingsItemPrivacyOn" = "Enabled";
|
||||||
"SettingsItemPrivacyOff" = "Disabled";
|
"SettingsItemPrivacyOff" = "Disabled";
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable @stylistic/max-len */
|
||||||
|
|
||||||
export { default as StarsGiftModal } from '../components/modals/stars/gift/StarsGiftModal';
|
export { default as StarsGiftModal } from '../components/modals/stars/gift/StarsGiftModal';
|
||||||
export { default as StarsGiftingPickerModal } from '../components/main/premium/StarsGiftingPickerModal';
|
export { default as StarsGiftingPickerModal } from '../components/main/premium/StarsGiftingPickerModal';
|
||||||
export { default as StarsBalanceModal } from '../components/modals/stars/StarsBalanceModal';
|
export { default as StarsBalanceModal } from '../components/modals/stars/StarsBalanceModal';
|
||||||
@ -12,6 +14,11 @@ export { default as GiftInfoValueModal } from '../components/modals/gift/value/G
|
|||||||
export { default as GiftLockedModal } from '../components/modals/gift/locked/GiftLockedModal';
|
export { default as GiftLockedModal } from '../components/modals/gift/locked/GiftLockedModal';
|
||||||
export { default as GiftResalePriceComposerModal } from '../components/modals/gift/resale/GiftResalePriceComposerModal';
|
export { default as GiftResalePriceComposerModal } from '../components/modals/gift/resale/GiftResalePriceComposerModal';
|
||||||
export { default as GiftUpgradeModal } from '../components/modals/gift/upgrade/GiftUpgradeModal';
|
export { default as GiftUpgradeModal } from '../components/modals/gift/upgrade/GiftUpgradeModal';
|
||||||
|
export { default as GiftAuctionModal } from '../components/modals/gift/auction/GiftAuctionModal';
|
||||||
|
export { default as GiftAuctionBidModal } from '../components/modals/gift/auction/GiftAuctionBidModal';
|
||||||
|
export { default as GiftAuctionInfoModal } from '../components/modals/gift/auction/GiftAuctionInfoModal';
|
||||||
|
export { default as GiftAuctionAcquiredModal } from '../components/modals/gift/auction/GiftAuctionAcquiredModal';
|
||||||
|
export { default as GiftAuctionChangeRecipientModal } from '../components/modals/gift/auction/GiftAuctionChangeRecipientModal';
|
||||||
export { default as StarGiftPriceDecreaseInfoModal } from '../components/modals/gift/StarGiftPriceDecreaseInfoModal';
|
export { default as StarGiftPriceDecreaseInfoModal } from '../components/modals/gift/StarGiftPriceDecreaseInfoModal';
|
||||||
export { default as GiftStatusInfoModal } from '../components/modals/gift/status/GiftStatusInfoModal';
|
export { default as GiftStatusInfoModal } from '../components/modals/gift/status/GiftStatusInfoModal';
|
||||||
export { default as GiftWithdrawModal } from '../components/modals/gift/withdraw/GiftWithdrawModal';
|
export { default as GiftWithdrawModal } from '../components/modals/gift/withdraw/GiftWithdrawModal';
|
||||||
|
|||||||
@ -15,6 +15,12 @@ export type GiftAttributes = {
|
|||||||
backdrop?: ApiStarGiftAttributeBackdrop;
|
backdrop?: ApiStarGiftAttributeBackdrop;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type GiftPreviewAttributes = {
|
||||||
|
model: ApiStarGiftAttributeModel;
|
||||||
|
pattern: ApiStarGiftAttributePattern;
|
||||||
|
backdrop: ApiStarGiftAttributeBackdrop;
|
||||||
|
};
|
||||||
|
|
||||||
export function getStickerFromGift(gift: ApiStarGift): ApiSticker | undefined {
|
export function getStickerFromGift(gift: ApiStarGift): ApiSticker | undefined {
|
||||||
if (gift.type === 'starGift') {
|
if (gift.type === 'starGift') {
|
||||||
return gift.sticker;
|
return gift.sticker;
|
||||||
@ -52,3 +58,46 @@ function getGiftAttributesFromList(attributes: ApiStarGiftAttribute[]) {
|
|||||||
backdrop,
|
backdrop,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getRandomGiftPreviewAttributes(
|
||||||
|
list: ApiStarGiftAttribute[],
|
||||||
|
previousSelection?: GiftPreviewAttributes,
|
||||||
|
): GiftPreviewAttributes {
|
||||||
|
const models = list.filter((attr): attr is ApiStarGiftAttributeModel => (
|
||||||
|
attr.type === 'model' && attr.name !== previousSelection?.model.name
|
||||||
|
));
|
||||||
|
const patterns = list.filter((attr): attr is ApiStarGiftAttributePattern => (
|
||||||
|
attr.type === 'pattern' && attr.name !== previousSelection?.pattern.name
|
||||||
|
));
|
||||||
|
const backdrops = list.filter((attr): attr is ApiStarGiftAttributeBackdrop => (
|
||||||
|
attr.type === 'backdrop' && attr.name !== previousSelection?.backdrop.name
|
||||||
|
));
|
||||||
|
|
||||||
|
if (!models.length || !patterns.length || !backdrops.length) {
|
||||||
|
// Fallback: re-filter without exclusions if any category is empty
|
||||||
|
const fallbackModels = models.length ? models
|
||||||
|
: list.filter((attr): attr is ApiStarGiftAttributeModel => attr.type === 'model');
|
||||||
|
|
||||||
|
const fallbackPatterns = patterns.length ? patterns
|
||||||
|
: list.filter((attr): attr is ApiStarGiftAttributePattern => attr.type === 'pattern');
|
||||||
|
|
||||||
|
const fallbackBackdrops = backdrops.length ? backdrops
|
||||||
|
: list.filter((attr): attr is ApiStarGiftAttributeBackdrop => attr.type === 'backdrop');
|
||||||
|
|
||||||
|
return {
|
||||||
|
model: fallbackModels[Math.floor(Math.random() * fallbackModels.length)],
|
||||||
|
pattern: fallbackPatterns[Math.floor(Math.random() * fallbackPatterns.length)],
|
||||||
|
backdrop: fallbackBackdrops[Math.floor(Math.random() * fallbackBackdrops.length)],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const randomModel = models[Math.floor(Math.random() * models.length)];
|
||||||
|
const randomPattern = patterns[Math.floor(Math.random() * patterns.length)];
|
||||||
|
const randomBackdrop = backdrops[Math.floor(Math.random() * backdrops.length)];
|
||||||
|
|
||||||
|
return {
|
||||||
|
model: randomModel,
|
||||||
|
pattern: randomPattern,
|
||||||
|
backdrop: randomBackdrop,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@ -42,6 +42,7 @@ const PickerModal = ({
|
|||||||
containerRef: dialogRef,
|
containerRef: dialogRef,
|
||||||
selector: `.modal-content ${itemsContainerSelector}`,
|
selector: `.modal-content ${itemsContainerSelector}`,
|
||||||
isBottomNotch: true,
|
isBottomNotch: true,
|
||||||
|
shouldHideTopNotch: true,
|
||||||
}, [modalProps.isOpen]);
|
}, [modalProps.isOpen]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import {
|
|||||||
import { addExtraClass } from '../../lib/teact/teact-dom';
|
import { addExtraClass } from '../../lib/teact/teact-dom';
|
||||||
import { getActions, getGlobal, withGlobal } from '../../global';
|
import { getActions, getGlobal, withGlobal } from '../../global';
|
||||||
|
|
||||||
import type { ApiChatFolder, ApiLimitTypeWithModal, ApiUser } from '../../api/types';
|
import type { ApiChatFolder, ApiLimitTypeWithModal, ApiStarGiftAuctionState, ApiUser } from '../../api/types';
|
||||||
import type { TabState } from '../../global/types';
|
import type { TabState } from '../../global/types';
|
||||||
|
|
||||||
import { BASE_EMOJI_KEYWORD_LANG, DEBUG, FOLDERS_POSITION_LEFT, INACTIVE_MARKER } from '../../config';
|
import { BASE_EMOJI_KEYWORD_LANG, DEBUG, FOLDERS_POSITION_LEFT, INACTIVE_MARKER } from '../../config';
|
||||||
@ -145,6 +145,7 @@ type StateProps = {
|
|||||||
isAccountFrozen?: boolean;
|
isAccountFrozen?: boolean;
|
||||||
isAppConfigLoaded?: boolean;
|
isAppConfigLoaded?: boolean;
|
||||||
isFoldersSidebarShown: boolean;
|
isFoldersSidebarShown: boolean;
|
||||||
|
activeGiftAuction?: ApiStarGiftAuctionState;
|
||||||
};
|
};
|
||||||
|
|
||||||
const APP_OUTDATED_TIMEOUT_MS = 5 * 60 * 1000; // 5 min
|
const APP_OUTDATED_TIMEOUT_MS = 5 * 60 * 1000; // 5 min
|
||||||
@ -198,6 +199,7 @@ const Main = ({
|
|||||||
isAccountFrozen,
|
isAccountFrozen,
|
||||||
isAppConfigLoaded,
|
isAppConfigLoaded,
|
||||||
isFoldersSidebarShown,
|
isFoldersSidebarShown,
|
||||||
|
activeGiftAuction,
|
||||||
}: OwnProps & StateProps) => {
|
}: OwnProps & StateProps) => {
|
||||||
const {
|
const {
|
||||||
initMain,
|
initMain,
|
||||||
@ -258,6 +260,7 @@ const Main = ({
|
|||||||
loadAllStories,
|
loadAllStories,
|
||||||
loadAllHiddenStories,
|
loadAllHiddenStories,
|
||||||
loadContentSettings,
|
loadContentSettings,
|
||||||
|
loadActiveGiftAuction,
|
||||||
loadPromoData,
|
loadPromoData,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
@ -439,6 +442,15 @@ const Main = ({
|
|||||||
});
|
});
|
||||||
}, [currentUserId]);
|
}, [currentUserId]);
|
||||||
|
|
||||||
|
// Refresh active gift auction subscription
|
||||||
|
const auctionTimeout = activeGiftAuction?.timeout;
|
||||||
|
const auctionGiftId = activeGiftAuction?.gift.id;
|
||||||
|
useInterval(() => {
|
||||||
|
if (auctionGiftId) {
|
||||||
|
loadActiveGiftAuction({ giftId: auctionGiftId });
|
||||||
|
}
|
||||||
|
}, auctionTimeout ? auctionTimeout * 1000 : undefined);
|
||||||
|
|
||||||
// Restore Transition slide class after async rendering
|
// Restore Transition slide class after async rendering
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const container = containerRef.current!;
|
const container = containerRef.current!;
|
||||||
@ -635,6 +647,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
payment,
|
payment,
|
||||||
limitReachedModal,
|
limitReachedModal,
|
||||||
deleteFolderDialogModal,
|
deleteFolderDialogModal,
|
||||||
|
activeGiftAuction,
|
||||||
} = selectTabState(global);
|
} = selectTabState(global);
|
||||||
|
|
||||||
const { wasTimeFormatSetManually, foldersPosition } = selectSharedSettings(global);
|
const { wasTimeFormatSetManually, foldersPosition } = selectSharedSettings(global);
|
||||||
@ -693,6 +706,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
isAccountFrozen,
|
isAccountFrozen,
|
||||||
isAppConfigLoaded: global.isAppConfigLoaded,
|
isAppConfigLoaded: global.isAppConfigLoaded,
|
||||||
isFoldersSidebarShown: foldersPosition === FOLDERS_POSITION_LEFT && !isMobile && selectAreFoldersPresent(global),
|
isFoldersSidebarShown: foldersPosition === FOLDERS_POSITION_LEFT && !isMobile && selectAreFoldersPresent(global),
|
||||||
|
activeGiftAuction,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(Main));
|
)(Main));
|
||||||
|
|||||||
@ -556,7 +556,7 @@ const ActionMessageText = ({
|
|||||||
|
|
||||||
case 'starGift': {
|
case 'starGift': {
|
||||||
const {
|
const {
|
||||||
gift, alreadyPaidUpgradeStars, peerId, savedId, fromId, isPrepaidUpgrade,
|
gift, alreadyPaidUpgradeStars, peerId, savedId, fromId, isPrepaidUpgrade, isAuctionAcquired,
|
||||||
} = action;
|
} = action;
|
||||||
const isToChannel = Boolean(peerId && savedId);
|
const isToChannel = Boolean(peerId && savedId);
|
||||||
|
|
||||||
@ -572,6 +572,10 @@ const ActionMessageText = ({
|
|||||||
const starsAmount = gift.stars + (alreadyPaidUpgradeStars || 0);
|
const starsAmount = gift.stars + (alreadyPaidUpgradeStars || 0);
|
||||||
const cost = renderStrong(formatStarsAsText(lang, starsAmount));
|
const cost = renderStrong(formatStarsAsText(lang, starsAmount));
|
||||||
|
|
||||||
|
if (isAuctionAcquired) {
|
||||||
|
return lang('ActionStarGiftAuctionWon', { cost }, { withNodes: true });
|
||||||
|
}
|
||||||
|
|
||||||
if (isPrepaidUpgrade && gift.upgradeStars) {
|
if (isPrepaidUpgrade && gift.upgradeStars) {
|
||||||
const upgradeCost = renderStrong(formatStarsAsText(lang, gift.upgradeStars));
|
const upgradeCost = renderStrong(formatStarsAsText(lang, gift.upgradeStars));
|
||||||
|
|
||||||
|
|||||||
@ -72,6 +72,11 @@
|
|||||||
opacity: 0.85;
|
opacity: 0.85;
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin-inline-end: 0.25rem;
|
||||||
|
font-size: 1rem !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.with-gift &--quick-button {
|
.with-gift &--quick-button {
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import buildClassName from '../../../util/buildClassName';
|
|||||||
import { tryParseDeepLink } from '../../../util/deepLinkParser';
|
import { tryParseDeepLink } from '../../../util/deepLinkParser';
|
||||||
import trimText from '../../../util/trimText';
|
import trimText from '../../../util/trimText';
|
||||||
import renderText from '../../common/helpers/renderText';
|
import renderText from '../../common/helpers/renderText';
|
||||||
import { getWebpageButtonLangKey } from './helpers/webpageType';
|
import { getWebpageButtonIcon, getWebpageButtonLangKey } from './helpers/webpageType';
|
||||||
|
|
||||||
import useDynamicColorListener from '../../../hooks/stickers/useDynamicColorListener';
|
import useDynamicColorListener from '../../../hooks/stickers/useDynamicColorListener';
|
||||||
import useEnsureStory from '../../../hooks/useEnsureStory';
|
import useEnsureStory from '../../../hooks/useEnsureStory';
|
||||||
@ -23,6 +23,7 @@ import useLastCallback from '../../../hooks/useLastCallback';
|
|||||||
import Audio from '../../common/Audio';
|
import Audio from '../../common/Audio';
|
||||||
import Document from '../../common/Document';
|
import Document from '../../common/Document';
|
||||||
import EmojiIconBackground from '../../common/embedded/EmojiIconBackground';
|
import EmojiIconBackground from '../../common/embedded/EmojiIconBackground';
|
||||||
|
import Icon from '../../common/icons/Icon';
|
||||||
import PeerColorWrapper from '../../common/PeerColorWrapper';
|
import PeerColorWrapper from '../../common/PeerColorWrapper';
|
||||||
import SafeLink from '../../common/SafeLink';
|
import SafeLink from '../../common/SafeLink';
|
||||||
import StickerView from '../../common/StickerView';
|
import StickerView from '../../common/StickerView';
|
||||||
@ -30,6 +31,7 @@ import Button from '../../ui/Button';
|
|||||||
import BaseStory from './BaseStory';
|
import BaseStory from './BaseStory';
|
||||||
import Photo from './Photo';
|
import Photo from './Photo';
|
||||||
import Video from './Video';
|
import Video from './Video';
|
||||||
|
import WebPageStarGiftAuction from './WebPageStarGiftAuction';
|
||||||
import WebPageUniqueGift from './WebPageUniqueGift';
|
import WebPageUniqueGift from './WebPageUniqueGift';
|
||||||
|
|
||||||
import './WebPage.scss';
|
import './WebPage.scss';
|
||||||
@ -37,6 +39,7 @@ import './WebPage.scss';
|
|||||||
const MAX_TEXT_LENGTH = 170; // symbols
|
const MAX_TEXT_LENGTH = 170; // symbols
|
||||||
const WEBPAGE_STORY_TYPE = 'telegram_story';
|
const WEBPAGE_STORY_TYPE = 'telegram_story';
|
||||||
const WEBPAGE_GIFT_TYPE = 'telegram_nft';
|
const WEBPAGE_GIFT_TYPE = 'telegram_nft';
|
||||||
|
const WEBPAGE_AUCTION_TYPE = 'telegram_auction';
|
||||||
const STICKER_SIZE = 80;
|
const STICKER_SIZE = 80;
|
||||||
const EMOJI_SIZE = 38;
|
const EMOJI_SIZE = 38;
|
||||||
|
|
||||||
@ -145,11 +148,14 @@ const WebPage: FC<OwnProps & StateProps> = ({
|
|||||||
const { mediaSize } = messageWebPage;
|
const { mediaSize } = messageWebPage;
|
||||||
const isStory = type === WEBPAGE_STORY_TYPE;
|
const isStory = type === WEBPAGE_STORY_TYPE;
|
||||||
const isGift = type === WEBPAGE_GIFT_TYPE;
|
const isGift = type === WEBPAGE_GIFT_TYPE;
|
||||||
|
const isAuction = type === WEBPAGE_AUCTION_TYPE;
|
||||||
const isExpiredStory = story && 'isDeleted' in story;
|
const isExpiredStory = story && 'isDeleted' in story;
|
||||||
|
|
||||||
const resultType = stickers?.isEmoji ? 'telegram_emojiset' : type;
|
const resultType = stickers?.isEmoji ? 'telegram_emojiset' : type;
|
||||||
const quickButtonLangKey = !isExpiredStory ? getWebpageButtonLangKey(resultType) : undefined;
|
const auctionEndDate = isAuction && webPage.auction ? webPage.auction.endDate : undefined;
|
||||||
|
const quickButtonLangKey = !isExpiredStory ? getWebpageButtonLangKey(resultType, auctionEndDate) : undefined;
|
||||||
const quickButtonTitle = quickButtonLangKey && lang(quickButtonLangKey);
|
const quickButtonTitle = quickButtonLangKey && lang(quickButtonLangKey);
|
||||||
|
const quickButtonIcon = getWebpageButtonIcon(resultType);
|
||||||
|
|
||||||
const truncatedDescription = trimText(description, MAX_TEXT_LENGTH);
|
const truncatedDescription = trimText(description, MAX_TEXT_LENGTH);
|
||||||
const isArticle = Boolean(truncatedDescription || title || siteName);
|
const isArticle = Boolean(truncatedDescription || title || siteName);
|
||||||
@ -167,20 +173,21 @@ const WebPage: FC<OwnProps & StateProps> = ({
|
|||||||
!isArticle && 'no-article',
|
!isArticle && 'no-article',
|
||||||
document && 'with-document',
|
document && 'with-document',
|
||||||
quickButtonTitle && 'with-quick-button',
|
quickButtonTitle && 'with-quick-button',
|
||||||
isGift && 'with-gift',
|
(isGift || isAuction) && 'with-gift',
|
||||||
);
|
);
|
||||||
|
|
||||||
function renderQuickButton(caption: string) {
|
function renderQuickButton() {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
className="WebPage--quick-button"
|
className="WebPage--quick-button"
|
||||||
size="tiny"
|
size="tiny"
|
||||||
color="translucent"
|
color="translucent"
|
||||||
isRectangular
|
isRectangular
|
||||||
noForcedUpperCase
|
noForcedUpperCase={!isAuction}
|
||||||
onClick={handleOpenTelegramLink}
|
onClick={handleOpenTelegramLink}
|
||||||
>
|
>
|
||||||
{caption}
|
{quickButtonIcon && <Icon name={quickButtonIcon} />}
|
||||||
|
{quickButtonTitle}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -195,7 +202,7 @@ const WebPage: FC<OwnProps & StateProps> = ({
|
|||||||
<div className={buildClassName(
|
<div className={buildClassName(
|
||||||
'WebPage--content',
|
'WebPage--content',
|
||||||
isStory && 'is-story',
|
isStory && 'is-story',
|
||||||
isGift && 'is-gift',
|
(isGift || isAuction) && 'is-gift',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{backgroundEmojiId && (
|
{backgroundEmojiId && (
|
||||||
@ -215,6 +222,14 @@ const WebPage: FC<OwnProps & StateProps> = ({
|
|||||||
onClick={handleOpenTelegramLink}
|
onClick={handleOpenTelegramLink}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{isAuction && webPage.auction && (
|
||||||
|
<WebPageStarGiftAuction
|
||||||
|
auction={webPage.auction}
|
||||||
|
observeIntersectionForLoading={observeIntersectionForLoading}
|
||||||
|
observeIntersectionForPlaying={observeIntersectionForPlaying}
|
||||||
|
onClick={handleOpenTelegramLink}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{isArticle && (
|
{isArticle && (
|
||||||
<div
|
<div
|
||||||
className={buildClassName('WebPage-text', 'WebPage-text_interactive')}
|
className={buildClassName('WebPage-text', 'WebPage-text_interactive')}
|
||||||
@ -224,12 +239,12 @@ const WebPage: FC<OwnProps & StateProps> = ({
|
|||||||
{title && (
|
{title && (
|
||||||
<p className="site-title">{renderText(title)}</p>
|
<p className="site-title">{renderText(title)}</p>
|
||||||
)}
|
)}
|
||||||
{truncatedDescription && !isGift && (
|
{truncatedDescription && !isGift && !isAuction && (
|
||||||
<p className="site-description">{renderText(truncatedDescription, ['emoji', 'br'])}</p>
|
<p className="site-description">{renderText(truncatedDescription, ['emoji', 'br'])}</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{photo && !isGift && !video && !document && (
|
{photo && !isGift && !isAuction && !video && !document && (
|
||||||
<Photo
|
<Photo
|
||||||
photo={photo}
|
photo={photo}
|
||||||
isOwn={message?.isOutgoing}
|
isOwn={message?.isOutgoing}
|
||||||
@ -310,7 +325,7 @@ const WebPage: FC<OwnProps & StateProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{quickButtonTitle && renderQuickButton(quickButtonTitle)}
|
{quickButtonTitle && renderQuickButton()}
|
||||||
</PeerColorWrapper>
|
</PeerColorWrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,69 @@
|
|||||||
|
.root {
|
||||||
|
cursor: var(--custom-cursor, pointer);
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
min-width: 12.5rem;
|
||||||
|
margin-top: 0;
|
||||||
|
padding-top: 2rem;
|
||||||
|
padding-bottom: 0.75rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
|
||||||
|
font-weight: var(--font-weight-semibold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.background {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stickerWrapper {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
width: 7.5rem;
|
||||||
|
height: 7.5rem;
|
||||||
|
margin-block: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
line-height: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
|
line-height: 1rem;
|
||||||
|
|
||||||
|
opacity: 0.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
top: 0.5rem;
|
||||||
|
left: 0.5rem;
|
||||||
|
|
||||||
|
padding: 0.125rem 0.375rem;
|
||||||
|
border-radius: 1rem;
|
||||||
|
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
|
line-height: 0.75rem;
|
||||||
|
|
||||||
|
backdrop-filter: blur(0.5rem);
|
||||||
|
}
|
||||||
103
src/components/middle/message/WebPageStarGiftAuction.tsx
Normal file
103
src/components/middle/message/WebPageStarGiftAuction.tsx
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import { memo, useMemo, useRef, useState } from '../../../lib/teact/teact';
|
||||||
|
|
||||||
|
import type { ApiWebPageAuctionData } from '../../../api/types';
|
||||||
|
|
||||||
|
import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
|
||||||
|
import buildClassName from '../../../util/buildClassName';
|
||||||
|
import { getServerTime } from '../../../util/serverTime';
|
||||||
|
|
||||||
|
import useFlag from '../../../hooks/useFlag';
|
||||||
|
import { type ObserveFn } from '../../../hooks/useIntersectionObserver';
|
||||||
|
import useLang from '../../../hooks/useLang';
|
||||||
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
|
|
||||||
|
import GiftEffectWrapper from '../../common/gift/GiftEffectWrapper';
|
||||||
|
import RadialPatternBackground from '../../common/profile/RadialPatternBackground';
|
||||||
|
import StickerView from '../../common/StickerView';
|
||||||
|
import TextTimer from '../../ui/TextTimer';
|
||||||
|
|
||||||
|
import styles from './WebPageStarGiftAuction.module.scss';
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
auction: ApiWebPageAuctionData;
|
||||||
|
observeIntersectionForLoading?: ObserveFn;
|
||||||
|
observeIntersectionForPlaying?: ObserveFn;
|
||||||
|
onClick?: NoneToVoidFunction;
|
||||||
|
};
|
||||||
|
|
||||||
|
const GIFT_STICKER_SIZE = 120;
|
||||||
|
const DEFAULT_CENTER_COLOR = '#254e7a';
|
||||||
|
const DEFAULT_EDGE_COLOR = '#0f2a49';
|
||||||
|
|
||||||
|
const WebPageStarGiftAuction = ({
|
||||||
|
auction,
|
||||||
|
observeIntersectionForLoading,
|
||||||
|
observeIntersectionForPlaying,
|
||||||
|
onClick,
|
||||||
|
}: OwnProps) => {
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
|
const stickerRef = useRef<HTMLDivElement>();
|
||||||
|
const [isHover, markHover, unmarkHover] = useFlag();
|
||||||
|
|
||||||
|
const { gift, endDate } = auction;
|
||||||
|
const { background, title, availabilityTotal, isSoldOut } = gift;
|
||||||
|
const textColor = background?.textColor || '#ffffff';
|
||||||
|
|
||||||
|
const [isFinished, setIsFinished] = useState(() => endDate < getServerTime());
|
||||||
|
|
||||||
|
const handleTimerEnd = useLastCallback(() => {
|
||||||
|
setIsFinished(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
const backgroundColors = useMemo(() => {
|
||||||
|
const centerColor = background?.centerColor || DEFAULT_CENTER_COLOR;
|
||||||
|
const edgeColor = background?.edgeColor || DEFAULT_EDGE_COLOR;
|
||||||
|
return [centerColor, edgeColor];
|
||||||
|
}, [background]);
|
||||||
|
|
||||||
|
const subtitleText = useMemo(() => {
|
||||||
|
if (isFinished || isSoldOut) {
|
||||||
|
return lang('GiftAuctionSoldOut');
|
||||||
|
}
|
||||||
|
return lang('GiftAuctionGifts', { count: availabilityTotal || 0 }, { pluralValue: availabilityTotal || 0 });
|
||||||
|
}, [availabilityTotal, isFinished, isSoldOut, lang]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={buildClassName('interactive-gift', styles.root)}
|
||||||
|
style={`color: ${textColor}`}
|
||||||
|
onClick={onClick}
|
||||||
|
onMouseEnter={!IS_TOUCH_ENV ? markHover : undefined}
|
||||||
|
onMouseLeave={!IS_TOUCH_ENV ? unmarkHover : undefined}
|
||||||
|
>
|
||||||
|
<RadialPatternBackground
|
||||||
|
className={styles.background}
|
||||||
|
backgroundColors={backgroundColors}
|
||||||
|
withAdaptiveHeight
|
||||||
|
/>
|
||||||
|
<div className={styles.badge} style={`background-color: ${backgroundColors[0]}`}>
|
||||||
|
{isFinished ? lang('GiftAuctionFinished') : <TextTimer endsAt={endDate} onEnd={handleTimerEnd} />}
|
||||||
|
</div>
|
||||||
|
<GiftEffectWrapper
|
||||||
|
ref={stickerRef}
|
||||||
|
className={styles.stickerWrapper}
|
||||||
|
withSparkles
|
||||||
|
sparklesColor={textColor}
|
||||||
|
>
|
||||||
|
<StickerView
|
||||||
|
containerRef={stickerRef}
|
||||||
|
sticker={gift.sticker}
|
||||||
|
size={GIFT_STICKER_SIZE}
|
||||||
|
shouldLoop={isHover}
|
||||||
|
observeIntersectionForPlaying={observeIntersectionForPlaying}
|
||||||
|
observeIntersectionForLoading={observeIntersectionForLoading}
|
||||||
|
/>
|
||||||
|
</GiftEffectWrapper>
|
||||||
|
<div className={styles.title}>{title}</div>
|
||||||
|
<div className={styles.subtitle}>{subtitleText}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(WebPageStarGiftAuction);
|
||||||
@ -27,7 +27,8 @@
|
|||||||
.message-content {
|
.message-content {
|
||||||
position: relative;
|
position: relative;
|
||||||
max-width: var(--max-width);
|
max-width: var(--max-width);
|
||||||
&.gift {
|
&.gift,
|
||||||
|
&.auction {
|
||||||
--max-width: 18rem;
|
--max-width: 18rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -72,23 +72,31 @@ const StarGiftAction = ({
|
|||||||
|
|
||||||
const peer = isOutgoing ? recipient : sender;
|
const peer = isOutgoing ? recipient : sender;
|
||||||
const isChannel = peer && isApiPeerChat(peer) && isChatChannel(peer);
|
const isChannel = peer && isApiPeerChat(peer) && isChatChannel(peer);
|
||||||
|
const isAuction = action.isAuctionAcquired;
|
||||||
|
|
||||||
const backgroundColor = useDynamicColorListener(ref, 'background-color', !action.gift.availabilityTotal);
|
const backgroundColor = useDynamicColorListener(ref, 'background-color', !action.gift.availabilityTotal);
|
||||||
|
|
||||||
const fallbackPeerTitle = lang('ActionFallbackSomeone');
|
const fallbackPeerTitle = lang('ActionFallbackSomeone');
|
||||||
const peerTitle = peer && getPeerTitle(lang, peer);
|
const peerTitle = peer && getPeerTitle(lang, peer);
|
||||||
|
const auctionToTitle = recipient && getPeerTitle(lang, recipient);
|
||||||
const isSelf = sender?.id === recipient?.id;
|
const isSelf = sender?.id === recipient?.id;
|
||||||
|
|
||||||
|
const auctionBid = isAuction ? action.gift.stars : undefined;
|
||||||
|
|
||||||
const giftDescription = useMemo(() => {
|
const giftDescription = useMemo(() => {
|
||||||
const peerLink = renderPeerLink(peer?.id, peerTitle || fallbackPeerTitle);
|
const peerLink = renderPeerLink(peer?.id, peerTitle || fallbackPeerTitle);
|
||||||
const starsAmount = action.starsToConvert !== undefined
|
const starsAmount = action.starsToConvert !== undefined
|
||||||
? formatStarsAsText(lang, action.starsToConvert) : undefined;
|
? formatStarsAsText(lang, action.starsToConvert) : undefined;
|
||||||
|
|
||||||
|
if (isAuction && auctionBid !== undefined) {
|
||||||
|
return lang('ActionStarGiftAuctionBought', { cost: formatStarsAsText(lang, auctionBid) });
|
||||||
|
}
|
||||||
|
|
||||||
if (action.isUpgraded) {
|
if (action.isUpgraded) {
|
||||||
return lang('ActionStarGiftUpgraded');
|
return lang('ActionStarGiftUpgraded');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.alreadyPaidUpgradeStars) {
|
if (action.alreadyPaidUpgradeStars && !isAuction) {
|
||||||
return translateWithYou(
|
return translateWithYou(
|
||||||
lang, 'ActionStarGiftUpgradeText', !isOutgoing || isSelf, { peer: peerLink },
|
lang, 'ActionStarGiftUpgradeText', !isOutgoing || isSelf, { peer: peerLink },
|
||||||
);
|
);
|
||||||
@ -100,7 +108,7 @@ const StarGiftAction = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (starGiftMaxConvertPeriod && getServerTime() < message.date + starGiftMaxConvertPeriod) {
|
if (starGiftMaxConvertPeriod && getServerTime() < message.date + starGiftMaxConvertPeriod && starsAmount) {
|
||||||
return translateWithYou(
|
return translateWithYou(
|
||||||
lang, 'ActionStarGiftConvertText', !isOutgoing || isSelf, { peer: peerLink, amount: starsAmount },
|
lang, 'ActionStarGiftConvertText', !isOutgoing || isSelf, { peer: peerLink, amount: starsAmount },
|
||||||
);
|
);
|
||||||
@ -116,8 +124,8 @@ const StarGiftAction = ({
|
|||||||
lang, 'ActionStarGiftNoConvertText', !isOutgoing || isSelf, { peer: peerLink },
|
lang, 'ActionStarGiftNoConvertText', !isOutgoing || isSelf, { peer: peerLink },
|
||||||
);
|
);
|
||||||
}, [
|
}, [
|
||||||
action, fallbackPeerTitle, isChannel, isOutgoing, lang, message.date, peer?.id, peerTitle, starGiftMaxConvertPeriod,
|
action, auctionBid, fallbackPeerTitle, isAuction, isChannel, isOutgoing, lang, message.date, peer?.id, peerTitle,
|
||||||
isSelf,
|
starGiftMaxConvertPeriod, isSelf,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -157,7 +165,11 @@ const StarGiftAction = ({
|
|||||||
)}
|
)}
|
||||||
<div className={styles.info}>
|
<div className={styles.info}>
|
||||||
<h3 className={styles.title}>
|
<h3 className={styles.title}>
|
||||||
{isSelf ? lang('ActionStarGiftSelf') : lang(
|
{isAuction && recipient ? lang(
|
||||||
|
'ActionStarGiftAuctionFor',
|
||||||
|
{ peer: renderPeerLink(recipient.id, auctionToTitle || fallbackPeerTitle) },
|
||||||
|
{ withNodes: true },
|
||||||
|
) : isSelf ? lang('ActionStarGiftSelf') : lang(
|
||||||
isOutgoing ? 'ActionStarGiftTo' : 'ActionStarGiftFrom',
|
isOutgoing ? 'ActionStarGiftTo' : 'ActionStarGiftFrom',
|
||||||
{
|
{
|
||||||
peer: renderPeerLink(peer?.id, peerTitle || fallbackPeerTitle),
|
peer: renderPeerLink(peer?.id, peerTitle || fallbackPeerTitle),
|
||||||
@ -188,7 +200,8 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
const messageSender = selectSender(global, message);
|
const messageSender = selectSender(global, message);
|
||||||
const giftSender = action.fromId ? selectPeer(global, action.fromId) : undefined;
|
const giftSender = action.fromId ? selectPeer(global, action.fromId) : undefined;
|
||||||
const messageRecipient = message.isOutgoing ? selectPeer(global, message.chatId) : currentUser;
|
const messageRecipient = message.isOutgoing ? selectPeer(global, message.chatId) : currentUser;
|
||||||
const giftRecipient = action.peerId ? selectPeer(global, action.peerId) : undefined;
|
const giftRecipientId = action.toId || action.peerId;
|
||||||
|
const giftRecipient = giftRecipientId ? selectPeer(global, giftRecipientId) : undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
canPlayAnimatedEmojis,
|
canPlayAnimatedEmojis,
|
||||||
|
|||||||
@ -144,6 +144,10 @@ export function buildContentClassName(
|
|||||||
if (webPage.gift) {
|
if (webPage.gift) {
|
||||||
classNames.push('gift');
|
classNames.push('gift');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (webPage.auction) {
|
||||||
|
classNames.push('auction');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invoice && !invoice.extendedMedia) {
|
if (invoice && !invoice.extendedMedia) {
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
|
import type { IconName } from '../../../../types/icons';
|
||||||
import type { RegularLangKey } from '../../../../types/language';
|
import type { RegularLangKey } from '../../../../types/language';
|
||||||
|
|
||||||
|
import { getServerTime } from '../../../../util/serverTime';
|
||||||
|
|
||||||
// https://github.com/telegramdesktop/tdesktop/blob/3da787791f6d227f69b32bf4003bc6071d05e2ac/Telegram/SourceFiles/history/view/history_view_view_button.cpp#L51
|
// https://github.com/telegramdesktop/tdesktop/blob/3da787791f6d227f69b32bf4003bc6071d05e2ac/Telegram/SourceFiles/history/view/history_view_view_button.cpp#L51
|
||||||
export function getWebpageButtonLangKey(type?: string): RegularLangKey | undefined {
|
export function getWebpageButtonLangKey(type?: string, auctionEndDate?: number): RegularLangKey | undefined {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'telegram_channel_request':
|
case 'telegram_channel_request':
|
||||||
case 'telegram_megagroup_request':
|
case 'telegram_megagroup_request':
|
||||||
@ -37,7 +40,18 @@ export function getWebpageButtonLangKey(type?: string): RegularLangKey | undefin
|
|||||||
return 'ViewButtonEmojiset';
|
return 'ViewButtonEmojiset';
|
||||||
case 'telegram_nft':
|
case 'telegram_nft':
|
||||||
return 'ViewButtonGiftUnique';
|
return 'ViewButtonGiftUnique';
|
||||||
|
case 'telegram_auction': {
|
||||||
|
const isFinished = auctionEndDate !== undefined && auctionEndDate * 1000 < getServerTime();
|
||||||
|
return isFinished ? 'PollViewResults' : 'GiftAuctionJoin';
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getWebpageButtonIcon(type?: string): IconName | undefined {
|
||||||
|
if (type === 'telegram_auction') {
|
||||||
|
return 'auction-filled';
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|||||||
@ -19,6 +19,11 @@ import CollectibleInfoModal from './collectible/CollectibleInfoModal.async';
|
|||||||
import DeleteAccountModal from './deleteAccount/DeleteAccountModal.async';
|
import DeleteAccountModal from './deleteAccount/DeleteAccountModal.async';
|
||||||
import EmojiStatusAccessModal from './emojiStatusAccess/EmojiStatusAccessModal.async';
|
import EmojiStatusAccessModal from './emojiStatusAccess/EmojiStatusAccessModal.async';
|
||||||
import FrozenAccountModal from './frozenAccount/FrozenAccountModal.async';
|
import FrozenAccountModal from './frozenAccount/FrozenAccountModal.async';
|
||||||
|
import GiftAuctionAcquiredModal from './gift/auction/GiftAuctionAcquiredModal.async';
|
||||||
|
import GiftAuctionBidModal from './gift/auction/GiftAuctionBidModal.async';
|
||||||
|
import GiftAuctionChangeRecipientModal from './gift/auction/GiftAuctionChangeRecipientModal.async';
|
||||||
|
import GiftAuctionInfoModal from './gift/auction/GiftAuctionInfoModal.async';
|
||||||
|
import GiftAuctionModal from './gift/auction/GiftAuctionModal.async';
|
||||||
import PremiumGiftModal from './gift/GiftModal.async';
|
import PremiumGiftModal from './gift/GiftModal.async';
|
||||||
import GiftInfoModal from './gift/info/GiftInfoModal.async';
|
import GiftInfoModal from './gift/info/GiftInfoModal.async';
|
||||||
import GiftLockedModal from './gift/locked/GiftLockedModal.async';
|
import GiftLockedModal from './gift/locked/GiftLockedModal.async';
|
||||||
@ -94,6 +99,11 @@ type ModalKey = keyof Pick<TabState,
|
|||||||
'locationAccessModal' |
|
'locationAccessModal' |
|
||||||
'aboutAdsModal' |
|
'aboutAdsModal' |
|
||||||
'giftUpgradeModal' |
|
'giftUpgradeModal' |
|
||||||
|
'giftAuctionModal' |
|
||||||
|
'giftAuctionBidModal' |
|
||||||
|
'giftAuctionInfoModal' |
|
||||||
|
'giftAuctionChangeRecipientModal' |
|
||||||
|
'giftAuctionAcquiredModal' |
|
||||||
'starGiftPriceDecreaseInfoModal' |
|
'starGiftPriceDecreaseInfoModal' |
|
||||||
'monetizationVerificationModal' |
|
'monetizationVerificationModal' |
|
||||||
'giftWithdrawModal' |
|
'giftWithdrawModal' |
|
||||||
@ -161,6 +171,11 @@ const MODALS: ModalRegistry = {
|
|||||||
locationAccessModal: LocationAccessModal,
|
locationAccessModal: LocationAccessModal,
|
||||||
aboutAdsModal: AboutAdsModal,
|
aboutAdsModal: AboutAdsModal,
|
||||||
giftUpgradeModal: GiftUpgradeModal,
|
giftUpgradeModal: GiftUpgradeModal,
|
||||||
|
giftAuctionModal: GiftAuctionModal,
|
||||||
|
giftAuctionBidModal: GiftAuctionBidModal,
|
||||||
|
giftAuctionInfoModal: GiftAuctionInfoModal,
|
||||||
|
giftAuctionChangeRecipientModal: GiftAuctionChangeRecipientModal,
|
||||||
|
giftAuctionAcquiredModal: GiftAuctionAcquiredModal,
|
||||||
starGiftPriceDecreaseInfoModal: StarGiftPriceDecreaseInfoModal,
|
starGiftPriceDecreaseInfoModal: StarGiftPriceDecreaseInfoModal,
|
||||||
monetizationVerificationModal: VerificationMonetizationModal,
|
monetizationVerificationModal: VerificationMonetizationModal,
|
||||||
giftWithdrawModal: GiftWithdrawModal,
|
giftWithdrawModal: GiftWithdrawModal,
|
||||||
|
|||||||
44
src/components/modals/common/TableInfo.module.scss
Normal file
44
src/components/modals/common/TableInfo.module.scss
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
.table {
|
||||||
|
overflow: hidden;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: max-content 1fr;
|
||||||
|
flex-shrink: 0;
|
||||||
|
gap: 1px;
|
||||||
|
|
||||||
|
border: 1px solid var(--color-borders);
|
||||||
|
border-radius: 1rem;
|
||||||
|
|
||||||
|
background-color: var(--color-borders);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
min-height: 2.5rem;
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
background-color: var(--color-background-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
min-width: 2rem;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
background-color: var(--color-background);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fullWidth {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatItem {
|
||||||
|
width: fit-content;
|
||||||
|
color: var(--color-primary);
|
||||||
|
background-color: var(--color-background);
|
||||||
|
}
|
||||||
64
src/components/modals/common/TableInfo.tsx
Normal file
64
src/components/modals/common/TableInfo.tsx
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import { memo, type TeactNode } from '../../../lib/teact/teact';
|
||||||
|
import { getActions } from '../../../global';
|
||||||
|
|
||||||
|
import buildClassName from '../../../util/buildClassName';
|
||||||
|
|
||||||
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
|
|
||||||
|
import PeerChip from '../../common/PeerChip';
|
||||||
|
|
||||||
|
import styles from './TableInfo.module.scss';
|
||||||
|
|
||||||
|
type ChatItem = { chatId: string; withEmojiStatus?: boolean };
|
||||||
|
|
||||||
|
export type TableData = [TeactNode | undefined, TeactNode | ChatItem][];
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
tableData?: TableData;
|
||||||
|
className?: string;
|
||||||
|
onChatClick?: (peerId: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const TableInfo = ({
|
||||||
|
tableData,
|
||||||
|
className,
|
||||||
|
onChatClick,
|
||||||
|
}: OwnProps) => {
|
||||||
|
const { openChat } = getActions();
|
||||||
|
|
||||||
|
const handleOpenChat = useLastCallback((peerId: string) => {
|
||||||
|
if (onChatClick) {
|
||||||
|
onChatClick(peerId);
|
||||||
|
} else {
|
||||||
|
openChat({ id: peerId });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!tableData?.length) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={buildClassName(styles.table, className)}>
|
||||||
|
{tableData.map(([label, value]) => (
|
||||||
|
<>
|
||||||
|
{Boolean(label) && <div className={buildClassName(styles.cell, styles.title)}>{label}</div>}
|
||||||
|
<div className={buildClassName(styles.cell, styles.value, !label && styles.fullWidth)}>
|
||||||
|
{typeof value === 'object' && 'chatId' in value ? (
|
||||||
|
<PeerChip
|
||||||
|
peerId={value.chatId}
|
||||||
|
className={styles.chatItem}
|
||||||
|
forceShowSelf
|
||||||
|
withEmojiStatus={value.withEmojiStatus}
|
||||||
|
clickArg={value.chatId}
|
||||||
|
onClick={handleOpenChat}
|
||||||
|
/>
|
||||||
|
) : value}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(TableInfo);
|
||||||
@ -1,5 +1,3 @@
|
|||||||
@use '../../../styles/mixins';
|
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -10,55 +8,10 @@
|
|||||||
padding-inline: 1rem !important;
|
padding-inline: 1rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
|
||||||
background-color: var(--color-background-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.value {
|
|
||||||
min-width: 2rem;
|
|
||||||
overflow-wrap: anywhere;
|
|
||||||
background-color: var(--color-background);
|
|
||||||
}
|
|
||||||
|
|
||||||
.table {
|
|
||||||
overflow: hidden;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: max-content 1fr;
|
|
||||||
flex-shrink: 0;
|
|
||||||
gap: 1px;
|
|
||||||
|
|
||||||
border: 1px solid var(--color-borders);
|
|
||||||
border-radius: 1rem;
|
|
||||||
|
|
||||||
background-color: var(--color-borders);
|
|
||||||
}
|
|
||||||
|
|
||||||
.noFooter {
|
.noFooter {
|
||||||
margin-top: 1.5rem;
|
margin-top: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cell {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
min-height: 2.5rem;
|
|
||||||
padding: 0.25rem 0.5rem;
|
|
||||||
|
|
||||||
font-size: 0.9375rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fullWidth {
|
|
||||||
grid-column: 1 / -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chatItem {
|
|
||||||
width: fit-content;
|
|
||||||
color: var(--color-primary);
|
|
||||||
background-color: var(--color-background);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -9,15 +9,13 @@ import buildClassName from '../../../util/buildClassName';
|
|||||||
import useLastCallback from '../../../hooks/useLastCallback';
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
|
|
||||||
import Avatar from '../../common/Avatar';
|
import Avatar from '../../common/Avatar';
|
||||||
import PeerChip from '../../common/PeerChip';
|
|
||||||
import Button from '../../ui/Button';
|
import Button from '../../ui/Button';
|
||||||
import Modal from '../../ui/Modal';
|
import Modal from '../../ui/Modal';
|
||||||
|
import TableInfo, { type TableData } from './TableInfo';
|
||||||
|
|
||||||
import styles from './TableInfoModal.module.scss';
|
import styles from './TableInfoModal.module.scss';
|
||||||
|
|
||||||
type ChatItem = { chatId: string; withEmojiStatus?: boolean };
|
export type { TableData };
|
||||||
|
|
||||||
export type TableData = [TeactNode | undefined, TeactNode | ChatItem][];
|
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
isOpen?: boolean;
|
isOpen?: boolean;
|
||||||
@ -59,7 +57,8 @@ const TableInfoModal = ({
|
|||||||
currencyInBalanceBar,
|
currencyInBalanceBar,
|
||||||
}: OwnProps) => {
|
}: OwnProps) => {
|
||||||
const { openChat } = getActions();
|
const { openChat } = getActions();
|
||||||
const handleOpenChat = useLastCallback((peerId: string) => {
|
|
||||||
|
const handleChatClick = useLastCallback((peerId: string) => {
|
||||||
openChat({ id: peerId });
|
openChat({ id: peerId });
|
||||||
onClose();
|
onClose();
|
||||||
});
|
});
|
||||||
@ -84,25 +83,7 @@ const TableInfoModal = ({
|
|||||||
<Avatar peer={headerAvatarPeer} size="jumbo" className={styles.avatar} />
|
<Avatar peer={headerAvatarPeer} size="jumbo" className={styles.avatar} />
|
||||||
)}
|
)}
|
||||||
{header}
|
{header}
|
||||||
<div className={buildClassName(styles.table, tableClassName)}>
|
<TableInfo tableData={tableData} className={tableClassName} onChatClick={handleChatClick} />
|
||||||
{tableData?.map(([label, value]) => (
|
|
||||||
<>
|
|
||||||
{Boolean(label) && <div className={buildClassName(styles.cell, styles.title)}>{label}</div>}
|
|
||||||
<div className={buildClassName(styles.cell, styles.value, !label && styles.fullWidth)}>
|
|
||||||
{typeof value === 'object' && 'chatId' in value ? (
|
|
||||||
<PeerChip
|
|
||||||
peerId={value.chatId}
|
|
||||||
className={styles.chatItem}
|
|
||||||
forceShowSelf
|
|
||||||
withEmojiStatus={value.withEmojiStatus}
|
|
||||||
clickArg={value.chatId}
|
|
||||||
onClick={handleOpenChat}
|
|
||||||
/>
|
|
||||||
) : value}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
{footer}
|
{footer}
|
||||||
{buttonText && (
|
{buttonText && (
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@ -144,6 +144,7 @@
|
|||||||
margin-inline-end: 0.125rem !important;
|
margin-inline-end: 0.125rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bottomDescription,
|
||||||
.description {
|
.description {
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
margin-left: 1rem;
|
margin-left: 1rem;
|
||||||
@ -151,12 +152,23 @@
|
|||||||
color: var(--color-text-secondary);
|
color: var(--color-text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bottomDescription {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.main-button {
|
.main-button {
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: var(--font-weight-semibold);
|
font-weight: var(--font-weight-semibold);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.buttonSubtitle {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-weight: var(--font-weight-normal);
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
.star {
|
.star {
|
||||||
--color-fill: var(--color-white);
|
--color-fill: var(--color-white);
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { getActions, withGlobal } from '../../../global';
|
|||||||
import type { ThemeKey } from '../../../types';
|
import type { ThemeKey } from '../../../types';
|
||||||
import type { GiftOption } from './GiftModal';
|
import type { GiftOption } from './GiftModal';
|
||||||
import {
|
import {
|
||||||
type ApiMessage, type ApiPeer, type ApiStarsAmount, MAIN_THREAD_ID,
|
type ApiMessage, type ApiPeer, type ApiStarGiftAuctionState, type ApiStarsAmount, MAIN_THREAD_ID,
|
||||||
} from '../../../api/types';
|
} from '../../../api/types';
|
||||||
|
|
||||||
import { getPeerTitle, isApiPeerUser } from '../../../global/helpers/peers';
|
import { getPeerTitle, isApiPeerUser } from '../../../global/helpers/peers';
|
||||||
@ -16,8 +16,11 @@ import {
|
|||||||
} from '../../../global/selectors';
|
} from '../../../global/selectors';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import buildStyle from '../../../util/buildStyle';
|
import buildStyle from '../../../util/buildStyle';
|
||||||
|
import { formatCountdown } from '../../../util/dates/dateFormat';
|
||||||
|
import { HOUR } from '../../../util/dates/units';
|
||||||
import { formatCurrency } from '../../../util/formatCurrency';
|
import { formatCurrency } from '../../../util/formatCurrency';
|
||||||
import { formatStarsAsIcon } from '../../../util/localization/format';
|
import { formatStarsAsIcon } from '../../../util/localization/format';
|
||||||
|
import { getServerTime } from '../../../util/serverTime';
|
||||||
|
|
||||||
import useCustomBackground from '../../../hooks/useCustomBackground';
|
import useCustomBackground from '../../../hooks/useCustomBackground';
|
||||||
import useLang from '../../../hooks/useLang';
|
import useLang from '../../../hooks/useLang';
|
||||||
@ -30,6 +33,7 @@ import Link from '../../ui/Link';
|
|||||||
import ListItem from '../../ui/ListItem';
|
import ListItem from '../../ui/ListItem';
|
||||||
import Switcher from '../../ui/Switcher';
|
import Switcher from '../../ui/Switcher';
|
||||||
import TextArea from '../../ui/TextArea';
|
import TextArea from '../../ui/TextArea';
|
||||||
|
import TextTimer from '../../ui/TextTimer';
|
||||||
|
|
||||||
import styles from './GiftComposer.module.scss';
|
import styles from './GiftComposer.module.scss';
|
||||||
|
|
||||||
@ -53,9 +57,11 @@ export type StateProps = {
|
|||||||
paidMessagesStars?: number;
|
paidMessagesStars?: number;
|
||||||
areUniqueStarGiftsDisallowed?: boolean;
|
areUniqueStarGiftsDisallowed?: boolean;
|
||||||
shouldDisallowLimitedStarGifts?: boolean;
|
shouldDisallowLimitedStarGifts?: boolean;
|
||||||
|
activeGiftAuction?: ApiStarGiftAuctionState;
|
||||||
};
|
};
|
||||||
|
|
||||||
const LIMIT_DISPLAY_THRESHOLD = 50;
|
const LIMIT_DISPLAY_THRESHOLD = 50;
|
||||||
|
const TEXT_TIMER_THRESHOLD = 48 * HOUR;
|
||||||
|
|
||||||
function GiftComposer({
|
function GiftComposer({
|
||||||
gift,
|
gift,
|
||||||
@ -74,9 +80,11 @@ function GiftComposer({
|
|||||||
paidMessagesStars,
|
paidMessagesStars,
|
||||||
areUniqueStarGiftsDisallowed,
|
areUniqueStarGiftsDisallowed,
|
||||||
shouldDisallowLimitedStarGifts,
|
shouldDisallowLimitedStarGifts,
|
||||||
|
activeGiftAuction,
|
||||||
}: OwnProps & StateProps) {
|
}: OwnProps & StateProps) {
|
||||||
const {
|
const {
|
||||||
sendStarGift, sendPremiumGiftByStars, openInvoice, openGiftUpgradeModal, openStarsBalanceModal,
|
sendStarGift, sendPremiumGiftByStars, openInvoice, openGiftUpgradeModal, openStarsBalanceModal,
|
||||||
|
openGiftAuctionBidModal, openGiftAuctionInfoModal, openGiftAuctionChangeRecipientModal,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
@ -180,7 +188,31 @@ function GiftComposer({
|
|||||||
openStarsBalanceModal({});
|
openStarsBalanceModal({});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleLearnMoreClick = useLastCallback(() => {
|
||||||
|
openGiftAuctionInfoModal({});
|
||||||
|
});
|
||||||
|
|
||||||
const handleMainButtonClick = useLastCallback(() => {
|
const handleMainButtonClick = useLastCallback(() => {
|
||||||
|
if (activeGiftAuction) {
|
||||||
|
const existingBidPeerId = activeGiftAuction.userState.bidPeerId;
|
||||||
|
if (existingBidPeerId && existingBidPeerId !== peerId) {
|
||||||
|
openGiftAuctionChangeRecipientModal({
|
||||||
|
oldPeerId: existingBidPeerId,
|
||||||
|
newPeerId: peerId,
|
||||||
|
message: giftMessage || undefined,
|
||||||
|
shouldHideName: shouldHideName || undefined,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
openGiftAuctionBidModal({
|
||||||
|
peerId,
|
||||||
|
message: giftMessage || undefined,
|
||||||
|
shouldHideName: shouldHideName || undefined,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isStarGift) {
|
if (isStarGift) {
|
||||||
sendStarGift({
|
sendStarGift({
|
||||||
peerId,
|
peerId,
|
||||||
@ -328,6 +360,12 @@ function GiftComposer({
|
|||||||
? formatStarsAsIcon(lang, gift.stars + (shouldPayForUpgrade ? gift.upgradeStars! : 0), { asFont: true })
|
? formatStarsAsIcon(lang, gift.stars + (shouldPayForUpgrade ? gift.upgradeStars! : 0), { asFont: true })
|
||||||
: isPremiumGift ? formatCurrency(lang, gift.amount, gift.currency) : undefined;
|
: isPremiumGift ? formatCurrency(lang, gift.amount, gift.currency) : undefined;
|
||||||
|
|
||||||
|
const giftsPerRound = activeGiftAuction?.gift.giftsPerRound;
|
||||||
|
const auctionEndDate = activeGiftAuction?.state.endDate;
|
||||||
|
const auctionTimeLeft = auctionEndDate ? auctionEndDate - getServerTime() : undefined;
|
||||||
|
const shouldUseTextTimer = auctionTimeLeft !== undefined && auctionTimeLeft > 0
|
||||||
|
&& auctionTimeLeft < TEXT_TIMER_THRESHOLD;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.footer}>
|
<div className={styles.footer}>
|
||||||
{isStarGift && Boolean(gift.availabilityRemains) && (
|
{isStarGift && Boolean(gift.availabilityRemains) && (
|
||||||
@ -341,13 +379,37 @@ function GiftComposer({
|
|||||||
className={styles.limited}
|
className={styles.limited}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{activeGiftAuction && Boolean(giftsPerRound) && (
|
||||||
|
<div className={styles.bottomDescription}>
|
||||||
|
{lang('GiftAuctionDescription', {
|
||||||
|
count: giftsPerRound,
|
||||||
|
link: <Link isPrimary onClick={handleLearnMoreClick}>{lang('GiftAuctionLearnMore')}</Link>,
|
||||||
|
}, { pluralValue: giftsPerRound, withNodes: true })}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<Button
|
<Button
|
||||||
className={styles.mainButton}
|
className={styles.mainButton}
|
||||||
size="smaller"
|
size={auctionTimeLeft ? undefined : 'smaller'}
|
||||||
onClick={handleMainButtonClick}
|
onClick={handleMainButtonClick}
|
||||||
isLoading={isPaymentFormLoading}
|
isLoading={isPaymentFormLoading}
|
||||||
|
noForcedUpperCase
|
||||||
>
|
>
|
||||||
{lang('GiftSend', {
|
{activeGiftAuction ? (
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
{lang('GiftAuctionPlaceBid')}
|
||||||
|
</div>
|
||||||
|
{auctionTimeLeft !== undefined && auctionTimeLeft > 0 && (
|
||||||
|
<div className={styles.buttonSubtitle}>
|
||||||
|
{lang('GiftAuctionTimeLeft', {
|
||||||
|
time: shouldUseTextTimer
|
||||||
|
? <TextTimer endsAt={auctionEndDate!} />
|
||||||
|
: formatCountdown(lang, auctionTimeLeft),
|
||||||
|
}, { withNodes: true })}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : lang('GiftSend', {
|
||||||
amount,
|
amount,
|
||||||
}, {
|
}, {
|
||||||
withNodes: true,
|
withNodes: true,
|
||||||
@ -434,6 +496,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
paidMessagesStars,
|
paidMessagesStars,
|
||||||
areUniqueStarGiftsDisallowed,
|
areUniqueStarGiftsDisallowed,
|
||||||
shouldDisallowLimitedStarGifts,
|
shouldDisallowLimitedStarGifts,
|
||||||
|
activeGiftAuction: tabState.activeGiftAuction,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(GiftComposer));
|
)(GiftComposer));
|
||||||
|
|||||||
@ -40,6 +40,14 @@
|
|||||||
&:hover::before {
|
&:hover::before {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.noClickable {
|
||||||
|
cursor: default;
|
||||||
|
|
||||||
|
&:hover::before {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.starGift {
|
.starGift {
|
||||||
@ -80,6 +88,7 @@
|
|||||||
font-size: 0.75rem !important;
|
font-size: 0.75rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.auction,
|
||||||
.premiumRequired {
|
.premiumRequired {
|
||||||
outline: 0.125rem solid #D18D21;
|
outline: 0.125rem solid #D18D21;
|
||||||
outline-offset: -0.125rem;
|
outline-offset: -0.125rem;
|
||||||
|
|||||||
@ -28,8 +28,10 @@ export type OwnProps = {
|
|||||||
gift: ApiStarGift;
|
gift: ApiStarGift;
|
||||||
isResale?: boolean;
|
isResale?: boolean;
|
||||||
withTransferBadge?: boolean;
|
withTransferBadge?: boolean;
|
||||||
|
hideBadge?: boolean;
|
||||||
|
noClickable?: boolean;
|
||||||
observeIntersection?: ObserveFn;
|
observeIntersection?: ObserveFn;
|
||||||
onClick: (gift: ApiStarGift, target: 'original' | 'resell') => void;
|
onClick?: (gift: ApiStarGift, target: 'original' | 'resell') => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
@ -39,9 +41,11 @@ type StateProps = {
|
|||||||
const GIFT_STICKER_SIZE = 90;
|
const GIFT_STICKER_SIZE = 90;
|
||||||
|
|
||||||
function GiftItemStar({
|
function GiftItemStar({
|
||||||
gift, isResale, isCurrentUserPremium, withTransferBadge, observeIntersection, onClick,
|
gift, isResale, isCurrentUserPremium, withTransferBadge, hideBadge, noClickable, observeIntersection, onClick,
|
||||||
}: OwnProps & StateProps) {
|
}: OwnProps & StateProps) {
|
||||||
const { openGiftInfoModal, openPremiumModal, showNotification, checkCanSendGift } = getActions();
|
const {
|
||||||
|
openGiftInfoModal, openPremiumModal, showNotification, checkCanSendGift, openGiftAuctionModal,
|
||||||
|
} = getActions();
|
||||||
|
|
||||||
const ref = useRef<HTMLDivElement>();
|
const ref = useRef<HTMLDivElement>();
|
||||||
const stickerRef = useRef<HTMLDivElement>();
|
const stickerRef = useRef<HTMLDivElement>();
|
||||||
@ -77,11 +81,17 @@ function GiftItemStar({
|
|||||||
? lang.number(resellMinStars) + '+' : priceInfo?.amount || 0;
|
? lang.number(resellMinStars) + '+' : priceInfo?.amount || 0;
|
||||||
const isLimited = !isGiftUnique && Boolean(regularGift?.isLimited);
|
const isLimited = !isGiftUnique && Boolean(regularGift?.isLimited);
|
||||||
const isSoldOut = !isGiftUnique && Boolean(regularGift?.isSoldOut);
|
const isSoldOut = !isGiftUnique && Boolean(regularGift?.isSoldOut);
|
||||||
|
const isAuction = !isGiftUnique && !isResale && Boolean(regularGift?.isAuction);
|
||||||
const isPremiumRequired = Boolean(gift?.requirePremium);
|
const isPremiumRequired = Boolean(gift?.requirePremium);
|
||||||
const isUserLimitReached = Boolean(regularGift?.limitedPerUser && !regularGift?.perUserRemains);
|
const isUserLimitReached = Boolean(regularGift?.limitedPerUser && !regularGift?.perUserRemains);
|
||||||
const perUserTotal = regularGift?.perUserTotal;
|
const perUserTotal = regularGift?.perUserTotal;
|
||||||
|
|
||||||
const handleGiftClick = useLastCallback(() => {
|
const handleGiftClick = useLastCallback(() => {
|
||||||
|
if (isAuction) {
|
||||||
|
openGiftAuctionModal({ gift });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isSoldOut && !isResale) {
|
if (isSoldOut && !isResale) {
|
||||||
openGiftInfoModal({ gift });
|
openGiftInfoModal({ gift });
|
||||||
return;
|
return;
|
||||||
@ -110,12 +120,12 @@ function GiftItemStar({
|
|||||||
if (isLocked) {
|
if (isLocked) {
|
||||||
checkCanSendGift({
|
checkCanSendGift({
|
||||||
gift,
|
gift,
|
||||||
onSuccess: () => onClick(gift, isResale ? 'resell' : 'original'),
|
onSuccess: () => onClick?.(gift, isResale ? 'resell' : 'original'),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
onClick(gift, isResale ? 'resell' : 'original');
|
onClick?.(gift, isResale ? 'resell' : 'original');
|
||||||
});
|
});
|
||||||
|
|
||||||
const radialPatternBackdrop = useMemo(() => {
|
const radialPatternBackdrop = useMemo(() => {
|
||||||
@ -162,14 +172,18 @@ function GiftItemStar({
|
|||||||
if (isSoldOut) {
|
if (isSoldOut) {
|
||||||
return <GiftRibbon color="red" text={lang('GiftSoldOut')} />;
|
return <GiftRibbon color="red" text={lang('GiftSoldOut')} />;
|
||||||
}
|
}
|
||||||
|
if (isAuction) {
|
||||||
|
return <GiftRibbon color="orange" text={lang('GiftRibbonAuction')} />;
|
||||||
|
}
|
||||||
if (isPremiumRequired) {
|
if (isPremiumRequired) {
|
||||||
return <GiftRibbon color="orange" text={lang('LimitPremium')} />;
|
return <GiftRibbon color="orange" text={lang('GiftRibbonPremium')} />;
|
||||||
}
|
}
|
||||||
if (isLimited) {
|
if (isLimited) {
|
||||||
return <GiftRibbon color="blue" text={lang('GiftLimited')} />;
|
return <GiftRibbon color="blue" text={lang('GiftLimited')} />;
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}, [isGiftUnique, isResale, gift, isSoldOut, isLimited, lang, giftNumber, isPremiumRequired]);
|
}, [isGiftUnique, isResale, gift, isSoldOut,
|
||||||
|
isLimited, lang, giftNumber, isPremiumRequired, isAuction]);
|
||||||
|
|
||||||
useOnIntersect(ref, observeIntersection, (entry) => {
|
useOnIntersect(ref, observeIntersection, (entry) => {
|
||||||
const visible = entry.isIntersecting;
|
const visible = entry.isIntersecting;
|
||||||
@ -181,6 +195,10 @@ function GiftItemStar({
|
|||||||
return lang('GiftTransferTitle');
|
return lang('GiftTransferTitle');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isAuction) {
|
||||||
|
return lang('GiftAuctionJoin');
|
||||||
|
}
|
||||||
|
|
||||||
if (priceCurrency === TON_CURRENCY_CODE) {
|
if (priceCurrency === TON_CURRENCY_CODE) {
|
||||||
return formatTonAsIcon(lang, formattedPrice || 0, {
|
return formatTonAsIcon(lang, formattedPrice || 0, {
|
||||||
shouldConvertFromNanos: true,
|
shouldConvertFromNanos: true,
|
||||||
@ -192,7 +210,7 @@ function GiftItemStar({
|
|||||||
asFont: true,
|
asFont: true,
|
||||||
className: styles.star,
|
className: styles.star,
|
||||||
});
|
});
|
||||||
}, [withTransferBadge, priceCurrency, formattedPrice, lang]);
|
}, [withTransferBadge, priceCurrency, formattedPrice, isAuction, lang]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -203,12 +221,14 @@ function GiftItemStar({
|
|||||||
styles.starGift,
|
styles.starGift,
|
||||||
'starGiftItem',
|
'starGiftItem',
|
||||||
isPremiumRequired && styles.premiumRequired,
|
isPremiumRequired && styles.premiumRequired,
|
||||||
|
isAuction && styles.auction,
|
||||||
|
noClickable && styles.noClickable,
|
||||||
)}
|
)}
|
||||||
tabIndex={0}
|
tabIndex={noClickable ? undefined : 0}
|
||||||
role="button"
|
role={noClickable ? undefined : 'button'}
|
||||||
onClick={handleGiftClick}
|
onClick={noClickable ? undefined : handleGiftClick}
|
||||||
onMouseEnter={!IS_TOUCH_ENV ? markHover : undefined}
|
onMouseEnter={!IS_TOUCH_ENV && !noClickable ? markHover : undefined}
|
||||||
onMouseLeave={!IS_TOUCH_ENV ? unmarkHover : undefined}
|
onMouseLeave={!IS_TOUCH_ENV && !noClickable ? unmarkHover : undefined}
|
||||||
>
|
>
|
||||||
{radialPatternBackdrop}
|
{radialPatternBackdrop}
|
||||||
|
|
||||||
@ -230,20 +250,22 @@ function GiftItemStar({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<Button
|
{!hideBadge && (
|
||||||
className={buildClassName(
|
<Button
|
||||||
styles.buy,
|
className={buildClassName(
|
||||||
withTransferBadge && styles.transferBadge,
|
styles.buy,
|
||||||
)}
|
withTransferBadge && styles.transferBadge,
|
||||||
nonInteractive
|
)}
|
||||||
size="tiny"
|
nonInteractive
|
||||||
color={isGiftUnique ? 'bluredStarsBadge' : 'stars'}
|
size="tiny"
|
||||||
withSparkleEffect={isVisible && !withTransferBadge}
|
color={isGiftUnique ? 'bluredStarsBadge' : 'stars'}
|
||||||
pill
|
withSparkleEffect={isVisible && !withTransferBadge}
|
||||||
fluid
|
pill
|
||||||
>
|
fluid
|
||||||
{badgeContent}
|
>
|
||||||
</Button>
|
{badgeContent}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
{giftRibbon}
|
{giftRibbon}
|
||||||
{isLocked && <Icon name="lock-badge" className={styles.lockIcon} />}
|
{isLocked && <Icon name="lock-badge" className={styles.lockIcon} />}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
.root :global(.modal-dialog),
|
.root :global(.modal-dialog),
|
||||||
.transition,
|
.transition,
|
||||||
.content {
|
.content {
|
||||||
height: min(92vh, 49rem);
|
height: min(98vh, 49rem);
|
||||||
max-height: none !important;
|
max-height: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -41,7 +41,7 @@ import InfiniteScroll from '../../ui/InfiniteScroll';
|
|||||||
import Modal from '../../ui/Modal';
|
import Modal from '../../ui/Modal';
|
||||||
import Transition from '../../ui/Transition';
|
import Transition from '../../ui/Transition';
|
||||||
import BalanceBlock from '../stars/BalanceBlock';
|
import BalanceBlock from '../stars/BalanceBlock';
|
||||||
import GiftSendingOptions from './GiftComposer';
|
import GiftComposer from './GiftComposer';
|
||||||
import GiftItemPremium from './GiftItemPremium';
|
import GiftItemPremium from './GiftItemPremium';
|
||||||
import GiftItemStar from './GiftItemStar';
|
import GiftItemStar from './GiftItemStar';
|
||||||
import GiftModalResaleScreen from './GiftModalResaleScreen';
|
import GiftModalResaleScreen from './GiftModalResaleScreen';
|
||||||
@ -104,6 +104,8 @@ const GiftModal: FC<OwnProps & StateProps> = ({
|
|||||||
closeResaleGiftsMarket,
|
closeResaleGiftsMarket,
|
||||||
loadMyUniqueGifts,
|
loadMyUniqueGifts,
|
||||||
openGiftTransferConfirmModal,
|
openGiftTransferConfirmModal,
|
||||||
|
setGiftModalSelectedGift,
|
||||||
|
clearActiveGiftAuction,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
const dialogRef = useRef<HTMLDivElement>();
|
const dialogRef = useRef<HTMLDivElement>();
|
||||||
const transitionRef = useRef<HTMLDivElement>();
|
const transitionRef = useRef<HTMLDivElement>();
|
||||||
@ -118,7 +120,7 @@ const GiftModal: FC<OwnProps & StateProps> = ({
|
|||||||
const user = peer && isApiPeerUser(peer) ? peer : undefined;
|
const user = peer && isApiPeerUser(peer) ? peer : undefined;
|
||||||
const chat = peer && isApiPeerChat(peer) ? peer : undefined;
|
const chat = peer && isApiPeerChat(peer) ? peer : undefined;
|
||||||
|
|
||||||
const [selectedGift, setSelectedGift] = useState<GiftOption | undefined>();
|
const selectedGift = renderingModal?.selectedGift;
|
||||||
const [shouldShowMainScreenHeader, setShouldShowMainScreenHeader] = useState(false);
|
const [shouldShowMainScreenHeader, setShouldShowMainScreenHeader] = useState(false);
|
||||||
const [isMainScreenHeaderForStarGifts, setIsMainScreenHeaderForStarGifts] = useState(false);
|
const [isMainScreenHeaderForStarGifts, setIsMainScreenHeaderForStarGifts] = useState(false);
|
||||||
const [isGiftScreenHeaderForStarGifts, setIsGiftScreenHeaderForStarGifts] = useState(false);
|
const [isGiftScreenHeaderForStarGifts, setIsGiftScreenHeaderForStarGifts] = useState(false);
|
||||||
@ -192,10 +194,14 @@ const GiftModal: FC<OwnProps & StateProps> = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
setShouldShowMainScreenHeader(false);
|
setShouldShowMainScreenHeader(false);
|
||||||
setSelectedGift(undefined);
|
setGiftModalSelectedGift({ gift: undefined });
|
||||||
setSelectedCategory('all');
|
setSelectedCategory('all');
|
||||||
}
|
}
|
||||||
}, [isOpen, tabId, closeResaleGiftsMarket]);
|
}, [isOpen]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsGiftScreenHeaderForStarGifts(Boolean(selectedGift && 'id' in selectedGift));
|
||||||
|
}, [selectedGift]);
|
||||||
|
|
||||||
const handleScroll = useLastCallback((e: React.UIEvent<HTMLDivElement>) => {
|
const handleScroll = useLastCallback((e: React.UIEvent<HTMLDivElement>) => {
|
||||||
if (isGiftScreen) return;
|
if (isGiftScreen) return;
|
||||||
@ -303,8 +309,7 @@ const GiftModal: FC<OwnProps & StateProps> = ({
|
|||||||
openGiftInMarket({ gift, tabId });
|
openGiftInMarket({ gift, tabId });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setSelectedGift(gift);
|
setGiftModalSelectedGift({ gift });
|
||||||
setIsGiftScreenHeaderForStarGifts('id' in gift);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleMyGiftClick = useLastCallback((gift: ApiStarGift) => {
|
const handleMyGiftClick = useLastCallback((gift: ApiStarGift) => {
|
||||||
@ -423,7 +428,7 @@ const GiftModal: FC<OwnProps & StateProps> = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleCloseModal = useLastCallback(() => {
|
const handleCloseModal = useLastCallback(() => {
|
||||||
setSelectedGift(undefined);
|
setGiftModalSelectedGift({ gift: undefined });
|
||||||
resetResaleGifts();
|
resetResaleGifts();
|
||||||
closeGiftModal();
|
closeGiftModal();
|
||||||
});
|
});
|
||||||
@ -434,7 +439,8 @@ const GiftModal: FC<OwnProps & StateProps> = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isGiftScreen) {
|
if (isGiftScreen) {
|
||||||
setSelectedGift(undefined);
|
setGiftModalSelectedGift({ gift: undefined });
|
||||||
|
clearActiveGiftAuction();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
handleCloseModal();
|
handleCloseModal();
|
||||||
@ -589,7 +595,7 @@ const GiftModal: FC<OwnProps & StateProps> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{isGiftScreen && renderingModal?.forPeerId && (
|
{isGiftScreen && renderingModal?.forPeerId && (
|
||||||
<GiftSendingOptions
|
<GiftComposer
|
||||||
gift={selectedGift}
|
gift={selectedGift}
|
||||||
giftByStars={giftsByStars.get(selectedGift)}
|
giftByStars={giftsByStars.get(selectedGift)}
|
||||||
peerId={renderingModal.forPeerId}
|
peerId={renderingModal.forPeerId}
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
import type { OwnProps } from './GiftAuctionAcquiredModal';
|
||||||
|
|
||||||
|
import { Bundles } from '../../../../util/moduleLoader';
|
||||||
|
|
||||||
|
import useModuleLoader from '../../../../hooks/useModuleLoader';
|
||||||
|
|
||||||
|
const GiftAuctionAcquiredModalAsync = (props: OwnProps) => {
|
||||||
|
const { modal } = props;
|
||||||
|
const GiftAuctionAcquiredModal = useModuleLoader(Bundles.Stars, 'GiftAuctionAcquiredModal', !modal);
|
||||||
|
|
||||||
|
return GiftAuctionAcquiredModal ? <GiftAuctionAcquiredModal {...props} /> : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GiftAuctionAcquiredModalAsync;
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
.modal {
|
||||||
|
max-width: 26rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-top: 0 !important;
|
||||||
|
padding-inline: 1.25rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.giftsListContainer {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.giftsList {
|
||||||
|
overflow-y: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
max-height: 29.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.giftHeader {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bidValue {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
margin-inline-start: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.starIcon {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.okButton {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
133
src/components/modals/gift/auction/GiftAuctionAcquiredModal.tsx
Normal file
133
src/components/modals/gift/auction/GiftAuctionAcquiredModal.tsx
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import { memo, useMemo, useRef } from '../../../../lib/teact/teact';
|
||||||
|
import { getActions, withGlobal } from '../../../../global';
|
||||||
|
|
||||||
|
import type { ApiStarGiftAuctionAcquiredGift, ApiSticker } from '../../../../api/types';
|
||||||
|
import type { TabState } from '../../../../global/types';
|
||||||
|
|
||||||
|
import { selectTabState } from '../../../../global/selectors';
|
||||||
|
import { formatDateTimeToString } from '../../../../util/dates/dateFormat';
|
||||||
|
import { formatStarsAsIcon } from '../../../../util/localization/format';
|
||||||
|
|
||||||
|
import useCurrentOrPrev from '../../../../hooks/useCurrentOrPrev';
|
||||||
|
import useLang from '../../../../hooks/useLang';
|
||||||
|
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||||
|
import useScrollNotch from '../../../../hooks/useScrollNotch';
|
||||||
|
|
||||||
|
import AnimatedIconFromSticker from '../../../common/AnimatedIconFromSticker';
|
||||||
|
import BadgeButton from '../../../common/BadgeButton';
|
||||||
|
import Button from '../../../ui/Button';
|
||||||
|
import Modal from '../../../ui/Modal';
|
||||||
|
import TableInfo, { type TableData } from '../../common/TableInfo';
|
||||||
|
|
||||||
|
import styles from './GiftAuctionAcquiredModal.module.scss';
|
||||||
|
|
||||||
|
export type OwnProps = {
|
||||||
|
modal: TabState['giftAuctionAcquiredModal'];
|
||||||
|
};
|
||||||
|
|
||||||
|
type StateProps = {
|
||||||
|
acquiredGifts?: ApiStarGiftAuctionAcquiredGift[];
|
||||||
|
giftTitle?: string;
|
||||||
|
giftSticker?: ApiSticker;
|
||||||
|
};
|
||||||
|
|
||||||
|
const GiftAuctionAcquiredModal = ({ modal, acquiredGifts, giftTitle, giftSticker }: OwnProps & StateProps) => {
|
||||||
|
const { closeGiftAuctionAcquiredModal } = getActions();
|
||||||
|
|
||||||
|
const containerRef = useRef<HTMLDivElement>();
|
||||||
|
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
|
const isOpen = Boolean(modal?.giftId);
|
||||||
|
const renderingGifts = useCurrentOrPrev(acquiredGifts);
|
||||||
|
const renderingGiftTitle = useCurrentOrPrev(giftTitle);
|
||||||
|
const renderingGiftSticker = useCurrentOrPrev(giftSticker);
|
||||||
|
|
||||||
|
const handleClose = useLastCallback(() => {
|
||||||
|
closeGiftAuctionAcquiredModal();
|
||||||
|
});
|
||||||
|
|
||||||
|
const giftItems = useMemo(() => {
|
||||||
|
if (!renderingGifts?.length) return undefined;
|
||||||
|
|
||||||
|
return renderingGifts.map((gift) => {
|
||||||
|
const header = lang('GiftAuctionBoughtGiftHeader', {
|
||||||
|
gift: renderingGiftTitle || lang('StarGift'),
|
||||||
|
giftNumber: gift.giftNumber ? lang.number(gift.giftNumber) : '',
|
||||||
|
round: lang.number(gift.round),
|
||||||
|
});
|
||||||
|
|
||||||
|
const tableData: TableData = [
|
||||||
|
[undefined, (
|
||||||
|
<span className={styles.giftHeader}>
|
||||||
|
{renderingGiftSticker && (
|
||||||
|
<AnimatedIconFromSticker
|
||||||
|
className={styles.giftSticker}
|
||||||
|
sticker={renderingGiftSticker}
|
||||||
|
size={20}
|
||||||
|
play={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<span>{header}</span>
|
||||||
|
</span>
|
||||||
|
)],
|
||||||
|
[lang('GiftAuctionRecipient'), { chatId: gift.peerId }],
|
||||||
|
[lang('GiftAuctionDate'), formatDateTimeToString(gift.date * 1000, lang.code, true)],
|
||||||
|
[lang('GiftAuctionAcceptedBid'), (
|
||||||
|
<span className={styles.bidValue}>
|
||||||
|
{formatStarsAsIcon(lang, gift.bidAmount, { className: styles.starIcon })}
|
||||||
|
<BadgeButton className={styles.badge}>
|
||||||
|
{lang('GiftAuctionTopPosition', { position: gift.position })}
|
||||||
|
</BadgeButton>
|
||||||
|
</span>
|
||||||
|
)],
|
||||||
|
];
|
||||||
|
|
||||||
|
return { tableData, key: `${gift.round}-${gift.giftNumber}` };
|
||||||
|
});
|
||||||
|
}, [renderingGifts, renderingGiftTitle, renderingGiftSticker, lang]);
|
||||||
|
|
||||||
|
const giftsCount = renderingGifts?.length || 0;
|
||||||
|
|
||||||
|
useScrollNotch({
|
||||||
|
containerRef,
|
||||||
|
selector: `.${styles.giftsList}`,
|
||||||
|
isBottomNotch: true,
|
||||||
|
}, [giftItems]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isOpen={isOpen}
|
||||||
|
hasCloseButton
|
||||||
|
title={lang('GiftAuctionBoughtGiftsTitle', { count: giftsCount }, { pluralValue: giftsCount })}
|
||||||
|
className={styles.modal}
|
||||||
|
contentClassName={styles.content}
|
||||||
|
onClose={handleClose}
|
||||||
|
isCondensedHeader
|
||||||
|
isSlim
|
||||||
|
>
|
||||||
|
<div className={styles.giftsListContainer} ref={containerRef}>
|
||||||
|
<div className={styles.giftsList}>
|
||||||
|
{giftItems?.map((item) => (
|
||||||
|
<TableInfo key={item.key} tableData={item.tableData} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button className={styles.okButton} onClick={handleClose}>
|
||||||
|
{lang('OK')}
|
||||||
|
</Button>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(withGlobal<OwnProps>(
|
||||||
|
(global): Complete<StateProps> => {
|
||||||
|
const { giftAuctionAcquiredModal } = selectTabState(global);
|
||||||
|
|
||||||
|
return {
|
||||||
|
acquiredGifts: giftAuctionAcquiredModal?.acquiredGifts,
|
||||||
|
giftTitle: giftAuctionAcquiredModal?.giftTitle,
|
||||||
|
giftSticker: giftAuctionAcquiredModal?.giftSticker,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
)(GiftAuctionAcquiredModal));
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
import type { OwnProps } from './GiftAuctionBidModal';
|
||||||
|
|
||||||
|
import { Bundles } from '../../../../util/moduleLoader';
|
||||||
|
|
||||||
|
import useModuleLoader from '../../../../hooks/useModuleLoader';
|
||||||
|
|
||||||
|
const GiftAuctionBidModalAsync = (props: OwnProps) => {
|
||||||
|
const { modal } = props;
|
||||||
|
const GiftAuctionBidModal = useModuleLoader(Bundles.Stars, 'GiftAuctionBidModal', !modal);
|
||||||
|
|
||||||
|
return GiftAuctionBidModal ? <GiftAuctionBidModal {...props} /> : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GiftAuctionBidModalAsync;
|
||||||
@ -0,0 +1,232 @@
|
|||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.25rem;
|
||||||
|
max-height: min(92vh, 38rem) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerControlPanel {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 3;
|
||||||
|
top: 0.75rem;
|
||||||
|
right: 1.25rem;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-top: 1rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
|
line-height: 1.5rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infoCards {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infoCard {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
padding: 0.75rem;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
background: var(--color-background-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.infoCardValue {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25rem;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
font-size: 1.125rem;
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.infoCardLabel {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1rem;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.winningStatus,
|
||||||
|
.bidderInfoSlide {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.winningText {
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
|
color: var(--color-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
.winningBadge {
|
||||||
|
padding: 0.0625rem 0.5rem;
|
||||||
|
border-radius: 0.875rem;
|
||||||
|
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 0.875rem;
|
||||||
|
color: var(--color-text-green);
|
||||||
|
|
||||||
|
background-color: rgba(var(--color-text-green-rgb), 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionTitle {
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionTitleTransition {
|
||||||
|
height: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bidderRow {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25rem;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.25rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bidderPosition {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
width: 1.5rem;
|
||||||
|
min-width: 1.5rem;
|
||||||
|
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bidderInfo {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
gap: 0.5rem;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
height: 2.125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bidderName {
|
||||||
|
overflow: hidden;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topBidderRow {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25rem;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
padding: 0.25rem 0;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 4.4375rem;
|
||||||
|
|
||||||
|
height: 1px;
|
||||||
|
|
||||||
|
opacity: 0.75;
|
||||||
|
background-color: var(--color-borders);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.topBidderPosition {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
width: 1.5rem;
|
||||||
|
min-width: 1.5rem;
|
||||||
|
|
||||||
|
font-size: 1.125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bidderAmount {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25rem;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonStar {
|
||||||
|
margin-inline-start: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.giftSticker {
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customBidInput {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
:global(.input-group) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.form-control) {
|
||||||
|
padding-left: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.customBidInputIcon {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
top: 50%;
|
||||||
|
left: 0.75rem;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
422
src/components/modals/gift/auction/GiftAuctionBidModal.tsx
Normal file
422
src/components/modals/gift/auction/GiftAuctionBidModal.tsx
Normal file
@ -0,0 +1,422 @@
|
|||||||
|
import { memo, useEffect, useMemo, useState } from '../../../../lib/teact/teact';
|
||||||
|
import { getActions, getGlobal, withGlobal } from '../../../../global';
|
||||||
|
|
||||||
|
import type {
|
||||||
|
ApiPeer,
|
||||||
|
ApiStarGiftAuctionState,
|
||||||
|
ApiStarsAmount,
|
||||||
|
} from '../../../../api/types';
|
||||||
|
import type { TabState } from '../../../../global/types';
|
||||||
|
|
||||||
|
import { selectPeer, selectTabState } from '../../../../global/selectors';
|
||||||
|
import { formatStarsAsIcon } from '../../../../util/localization/format';
|
||||||
|
import renderText from '../../../common/helpers/renderText';
|
||||||
|
|
||||||
|
import { useTransitionActiveKey } from '../../../../hooks/animations/useTransitionActiveKey';
|
||||||
|
import useCurrentOrPrev from '../../../../hooks/useCurrentOrPrev';
|
||||||
|
import useFlag from '../../../../hooks/useFlag';
|
||||||
|
import useLang from '../../../../hooks/useLang';
|
||||||
|
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||||
|
|
||||||
|
import AnimatedCounter from '../../../common/AnimatedCounter';
|
||||||
|
import AnimatedIconFromSticker from '../../../common/AnimatedIconFromSticker';
|
||||||
|
import Avatar from '../../../common/Avatar';
|
||||||
|
import FullNameTitle from '../../../common/FullNameTitle';
|
||||||
|
import StarIcon from '../../../common/icons/StarIcon';
|
||||||
|
import Button from '../../../ui/Button';
|
||||||
|
import ConfirmDialog from '../../../ui/ConfirmDialog';
|
||||||
|
import InputText from '../../../ui/InputText';
|
||||||
|
import Modal from '../../../ui/Modal';
|
||||||
|
import TextTimer from '../../../ui/TextTimer';
|
||||||
|
import Transition from '../../../ui/Transition';
|
||||||
|
import StarSlider from '../../paidReaction/StarSlider';
|
||||||
|
import BalanceBlock from '../../stars/BalanceBlock';
|
||||||
|
|
||||||
|
import styles from './GiftAuctionBidModal.module.scss';
|
||||||
|
|
||||||
|
export type OwnProps = {
|
||||||
|
modal: TabState['giftAuctionBidModal'];
|
||||||
|
};
|
||||||
|
|
||||||
|
type StateProps = {
|
||||||
|
auctionState?: ApiStarGiftAuctionState;
|
||||||
|
starBalance?: ApiStarsAmount;
|
||||||
|
currentUserPeer?: ApiPeer;
|
||||||
|
topBidderIds?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const DEFAULT_BID_AMOUNT = 50;
|
||||||
|
const MAX_BID_AMOUNT_STEP = 50000;
|
||||||
|
const MAX_CUSTOM_BID_AMOUNT = 1000000000;
|
||||||
|
const BID_ROUNDING_STEP = 10000;
|
||||||
|
const MIN_SLIDER_PROGRESS = 0.25;
|
||||||
|
const GIFT_STICKER_SIZE = 24;
|
||||||
|
const DEFAULT_TOP_BIDDERS_COUNT = 3;
|
||||||
|
|
||||||
|
const GiftAuctionBidModal = ({
|
||||||
|
modal,
|
||||||
|
auctionState,
|
||||||
|
starBalance,
|
||||||
|
currentUserPeer,
|
||||||
|
topBidderIds,
|
||||||
|
}: OwnProps & StateProps) => {
|
||||||
|
const { closeGiftAuctionBidModal, sendStarGiftAuctionBid, loadActiveGiftAuction } = getActions();
|
||||||
|
|
||||||
|
const isOpen = Boolean(modal?.isOpen);
|
||||||
|
|
||||||
|
const renderingAuctionState = useCurrentOrPrev(auctionState);
|
||||||
|
const renderingTopBidderIds = useCurrentOrPrev(topBidderIds);
|
||||||
|
|
||||||
|
const renderingTopBidderPeers = useMemo(() => {
|
||||||
|
if (!renderingTopBidderIds) return undefined;
|
||||||
|
const global = getGlobal();
|
||||||
|
return renderingTopBidderIds
|
||||||
|
.map((id) => selectPeer(global, id))
|
||||||
|
.filter(Boolean);
|
||||||
|
}, [renderingTopBidderIds]);
|
||||||
|
|
||||||
|
const [topBidder1, topBidder2, topBidder3] = renderingTopBidderPeers || [];
|
||||||
|
|
||||||
|
const topBidder1Key = useTransitionActiveKey([topBidder1?.id || '0']);
|
||||||
|
const topBidder2Key = useTransitionActiveKey([topBidder2?.id || '0']);
|
||||||
|
const topBidder3Key = useTransitionActiveKey([topBidder3?.id || '0']);
|
||||||
|
|
||||||
|
const giftsPerRound = renderingAuctionState?.gift.giftsPerRound || 0;
|
||||||
|
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
|
const activeState = renderingAuctionState?.state.type === 'active'
|
||||||
|
? renderingAuctionState.state
|
||||||
|
: undefined;
|
||||||
|
const userState = renderingAuctionState?.userState;
|
||||||
|
|
||||||
|
const [selectedBidAmount, setSelectedBidAmount] = useState(DEFAULT_BID_AMOUNT);
|
||||||
|
const [isCustomBidModalOpen, openCustomBidModal, closeCustomBidModal] = useFlag();
|
||||||
|
const [customBidValue, setCustomBidValue] = useState('');
|
||||||
|
|
||||||
|
const baseMinBid = activeState?.minBidAmount || DEFAULT_BID_AMOUNT;
|
||||||
|
|
||||||
|
const currentMinBid = userState?.minBidAmount || baseMinBid;
|
||||||
|
|
||||||
|
const sliderMaxValue = Math.ceil(currentMinBid / BID_ROUNDING_STEP) * BID_ROUNDING_STEP + MAX_BID_AMOUNT_STEP;
|
||||||
|
|
||||||
|
const currentProgress = (currentMinBid - baseMinBid) / (sliderMaxValue - baseMinBid);
|
||||||
|
const adjustedMinBid = Math.floor(
|
||||||
|
(currentMinBid - MIN_SLIDER_PROGRESS * sliderMaxValue) / (1 - MIN_SLIDER_PROGRESS),
|
||||||
|
);
|
||||||
|
const giftMinBid = currentProgress > MIN_SLIDER_PROGRESS
|
||||||
|
? Math.max(1, adjustedMinBid)
|
||||||
|
: baseMinBid;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSelectedBidAmount(currentMinBid);
|
||||||
|
}, [currentMinBid]);
|
||||||
|
|
||||||
|
const nextRoundAt = activeState?.nextRoundAt;
|
||||||
|
|
||||||
|
const bidDifference = userState?.bidAmount ? selectedBidAmount - userState.bidAmount : 0;
|
||||||
|
const isAtMaxValue = selectedBidAmount >= sliderMaxValue;
|
||||||
|
|
||||||
|
const sliderSecondaryText = useMemo(() => {
|
||||||
|
if (isAtMaxValue) return lang('GiftAuctionTapToBidMore');
|
||||||
|
if (bidDifference <= 0) return undefined;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
+
|
||||||
|
<AnimatedCounter text={lang.number(bidDifference)} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}, [bidDifference, isAtMaxValue, lang]);
|
||||||
|
|
||||||
|
const handleAmountChange = useLastCallback((value: number) => {
|
||||||
|
setSelectedBidAmount(value);
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleTimerEnd = useLastCallback(() => {
|
||||||
|
if (!renderingAuctionState?.gift.id) return;
|
||||||
|
loadActiveGiftAuction({ giftId: renderingAuctionState.gift.id });
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleBadgeClick = useLastCallback(() => {
|
||||||
|
if (isAtMaxValue) {
|
||||||
|
openCustomBidModal();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleCustomBidChange = useLastCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const value = e.target.value.replace(/\D/g, '');
|
||||||
|
const numValue = Number(value);
|
||||||
|
if (numValue > MAX_CUSTOM_BID_AMOUNT) return;
|
||||||
|
setCustomBidValue(value);
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleCustomBidSubmit = useLastCallback(() => {
|
||||||
|
if (!renderingAuctionState?.gift.id || !modal) return;
|
||||||
|
|
||||||
|
const resultValue = Number(customBidValue);
|
||||||
|
if (resultValue < currentMinBid) return;
|
||||||
|
|
||||||
|
setSelectedBidAmount(resultValue);
|
||||||
|
closeCustomBidModal();
|
||||||
|
|
||||||
|
setCustomBidValue('');
|
||||||
|
|
||||||
|
const { peerId, message, shouldHideName } = modal;
|
||||||
|
const isUpdateBid = Boolean(userState?.bidAmount);
|
||||||
|
|
||||||
|
sendStarGiftAuctionBid({
|
||||||
|
giftId: renderingAuctionState.gift.id,
|
||||||
|
bidAmount: resultValue,
|
||||||
|
peerId,
|
||||||
|
message: message ? { text: message } : undefined,
|
||||||
|
shouldHideName,
|
||||||
|
isUpdateBid,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleSubmit = useLastCallback(() => {
|
||||||
|
if (!renderingAuctionState?.gift.id || !modal) return;
|
||||||
|
const { peerId, message, shouldHideName } = modal;
|
||||||
|
const isUpdateBid = Boolean(userState?.bidAmount);
|
||||||
|
|
||||||
|
sendStarGiftAuctionBid({
|
||||||
|
giftId: renderingAuctionState.gift.id,
|
||||||
|
bidAmount: selectedBidAmount,
|
||||||
|
peerId,
|
||||||
|
message: message ? { text: message } : undefined,
|
||||||
|
shouldHideName,
|
||||||
|
isUpdateBid,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const userPosition = useMemo(() => {
|
||||||
|
if (!selectedBidAmount || !activeState?.bidLevels?.length) return undefined;
|
||||||
|
|
||||||
|
const { bidLevels } = activeState;
|
||||||
|
const userBidDate = userState?.bidDate || Number.MAX_SAFE_INTEGER;
|
||||||
|
|
||||||
|
for (const level of bidLevels) {
|
||||||
|
if (level.amount < selectedBidAmount
|
||||||
|
|| (level.amount === selectedBidAmount && level.date >= userBidDate)) {
|
||||||
|
return level.pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bidLevels[bidLevels.length - 1].pos + 1;
|
||||||
|
}, [selectedBidAmount, activeState, userState?.bidDate]);
|
||||||
|
|
||||||
|
function renderInfoCards() {
|
||||||
|
return (
|
||||||
|
<div className={styles.infoCards}>
|
||||||
|
<div className={styles.infoCard}>
|
||||||
|
<div className={styles.infoCardValue}>
|
||||||
|
<StarIcon type="gold" size="adaptive" />
|
||||||
|
{lang.number(currentMinBid)}
|
||||||
|
</div>
|
||||||
|
<div className={styles.infoCardLabel}>{lang('GiftAuctionMinimumBid')}</div>
|
||||||
|
</div>
|
||||||
|
<div className={styles.infoCard}>
|
||||||
|
<div className={styles.infoCardValue}>
|
||||||
|
<TextTimer endsAt={nextRoundAt || 0} shouldShowZeroOnEnd onEnd={handleTimerEnd} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.infoCardLabel}>{lang('GiftAuctionUntilNextRound')}</div>
|
||||||
|
</div>
|
||||||
|
<div className={styles.infoCard}>
|
||||||
|
<div className={styles.infoCardValue}>
|
||||||
|
<AnimatedIconFromSticker
|
||||||
|
noLoop={false}
|
||||||
|
className={styles.giftSticker}
|
||||||
|
sticker={renderingAuctionState?.gift.sticker}
|
||||||
|
size={GIFT_STICKER_SIZE}
|
||||||
|
/>
|
||||||
|
{lang.number(activeState?.giftsLeft || 0)}
|
||||||
|
</div>
|
||||||
|
<div className={styles.infoCardLabel}>{lang('GiftAuctionLeft')}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isWinning = Boolean(userState?.bidAmount && userPosition && userPosition <= giftsPerRound);
|
||||||
|
|
||||||
|
function renderCurrentBidSectionTitle() {
|
||||||
|
const giftTitle = renderingAuctionState?.gift.title || lang('StarGift');
|
||||||
|
const nextGiftNum = userPosition && userPosition <= 100
|
||||||
|
? (activeState?.lastGiftNum || 0) + userPosition
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Transition
|
||||||
|
name="fade"
|
||||||
|
activeKey={isWinning ? 0 : 1}
|
||||||
|
className={styles.sectionTitleTransition}
|
||||||
|
slideClassName={styles.bidderInfoSlide}
|
||||||
|
>
|
||||||
|
{isWinning ? (
|
||||||
|
<div className={styles.winningStatus}>
|
||||||
|
<span className={styles.winningText}>{lang('GiftAuctionYoureWinning')}</span>
|
||||||
|
<span className={styles.winningBadge}>
|
||||||
|
{lang('GiftUnique', { title: giftTitle, number: nextGiftNum ? lang.number(nextGiftNum) : undefined })}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className={styles.sectionTitle}>{lang('GiftAuctionYourBidWillBe')}</div>
|
||||||
|
)}
|
||||||
|
</Transition>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderUserBid() {
|
||||||
|
return (
|
||||||
|
<div className={styles.section}>
|
||||||
|
{renderCurrentBidSectionTitle()}
|
||||||
|
<div className={styles.bidderRow}>
|
||||||
|
<div className={styles.bidderPosition}>
|
||||||
|
{userPosition && userPosition > 100 ? `${userPosition}+` : (userPosition || 1)}
|
||||||
|
</div>
|
||||||
|
<div className={styles.bidderInfo}>
|
||||||
|
{currentUserPeer && <Avatar peer={currentUserPeer} size="small" />}
|
||||||
|
{currentUserPeer && <FullNameTitle peer={currentUserPeer} className={styles.bidderName} />}
|
||||||
|
</div>
|
||||||
|
<div className={styles.bidderAmount}>
|
||||||
|
<StarIcon type="gold" size="adaptive" />
|
||||||
|
{lang.number(selectedBidAmount)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTopBidderRow(
|
||||||
|
index: number,
|
||||||
|
emoji: string,
|
||||||
|
peer: ApiPeer | undefined,
|
||||||
|
amount: number | undefined,
|
||||||
|
activeKey: number,
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<div className={styles.topBidderRow} key={index}>
|
||||||
|
<div className={styles.topBidderPosition}>
|
||||||
|
{renderText(emoji, ['emoji'])}
|
||||||
|
</div>
|
||||||
|
<Transition
|
||||||
|
name="fade"
|
||||||
|
activeKey={activeKey}
|
||||||
|
className={styles.bidderInfo}
|
||||||
|
slideClassName={styles.bidderInfoSlide}
|
||||||
|
>
|
||||||
|
{peer && (
|
||||||
|
<>
|
||||||
|
<Avatar peer={peer} size="small" />
|
||||||
|
<FullNameTitle peer={peer} className={styles.bidderName} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Transition>
|
||||||
|
{amount !== undefined && (
|
||||||
|
<div className={styles.bidderAmount}>
|
||||||
|
<StarIcon type="gold" size="adaptive" />
|
||||||
|
{lang.number(amount)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTopWinners() {
|
||||||
|
const topCount = DEFAULT_TOP_BIDDERS_COUNT;
|
||||||
|
const bidLevels = activeState?.bidLevels;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.section}>
|
||||||
|
<div className={styles.sectionTitle}>
|
||||||
|
{lang('GiftAuctionTopWinners', { count: topCount }, { pluralValue: topCount })}
|
||||||
|
</div>
|
||||||
|
{renderTopBidderRow(0, '🥇', topBidder1, bidLevels?.[0]?.amount, topBidder1Key)}
|
||||||
|
{renderTopBidderRow(1, '🥈', topBidder2, bidLevels?.[1]?.amount, topBidder2Key)}
|
||||||
|
{renderTopBidderRow(2, '🥉', topBidder3, bidLevels?.[2]?.amount, topBidder3Key)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isOpen={isOpen}
|
||||||
|
hasAbsoluteCloseButton
|
||||||
|
isSlim
|
||||||
|
contentClassName={styles.content}
|
||||||
|
onClose={closeGiftAuctionBidModal}
|
||||||
|
isLowStackPriority
|
||||||
|
>
|
||||||
|
<div className={styles.headerControlPanel}>
|
||||||
|
<BalanceBlock balance={starBalance} className={styles.modalBalance} withAddButton />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<StarSlider
|
||||||
|
className={styles.slider}
|
||||||
|
defaultValue={currentMinBid}
|
||||||
|
minValue={giftMinBid}
|
||||||
|
minAllowedValue={currentMinBid}
|
||||||
|
maxValue={sliderMaxValue}
|
||||||
|
floatingBadgeDescription={sliderSecondaryText}
|
||||||
|
onChange={handleAmountChange}
|
||||||
|
onBadgeClick={handleBadgeClick}
|
||||||
|
shouldUseDynamicColor
|
||||||
|
shouldAllowCustomValue
|
||||||
|
/>
|
||||||
|
|
||||||
|
<h3 className={styles.title}>{lang('GiftAuctionPlaceBid')}</h3>
|
||||||
|
{renderInfoCards()}
|
||||||
|
|
||||||
|
{renderUserBid()}
|
||||||
|
{renderTopWinners()}
|
||||||
|
|
||||||
|
<Button noForcedUpperCase onClick={handleSubmit}>
|
||||||
|
{lang(userState?.bidAmount ? 'GiftAuctionAddToBid' : 'GiftAuctionPlaceBidButton', {
|
||||||
|
amount: formatStarsAsIcon(lang,
|
||||||
|
userState?.bidAmount ? selectedBidAmount - userState.bidAmount : selectedBidAmount,
|
||||||
|
{ asFont: true, className: styles.buttonStar }),
|
||||||
|
}, { withNodes: true })}
|
||||||
|
</Button>
|
||||||
|
<ConfirmDialog
|
||||||
|
isOpen={isCustomBidModalOpen}
|
||||||
|
title={lang('GiftAuctionCustomBidTitle')}
|
||||||
|
confirmLabel={lang('GiftAuctionCustomBidButton')}
|
||||||
|
isConfirmDisabled={!customBidValue || Number(customBidValue) < currentMinBid}
|
||||||
|
confirmHandler={handleCustomBidSubmit}
|
||||||
|
onClose={closeCustomBidModal}
|
||||||
|
>
|
||||||
|
<p>{lang('GiftAuctionCustomBidDescription', { count: renderingAuctionState?.gift.giftsPerRound })}</p>
|
||||||
|
<div className={styles.customBidInput}>
|
||||||
|
<StarIcon type="gold" size="adaptive" className={styles.customBidInputIcon} />
|
||||||
|
<InputText
|
||||||
|
value={customBidValue}
|
||||||
|
onChange={handleCustomBidChange}
|
||||||
|
placeholder={lang('GiftAuctionCustomBidPlaceholder')}
|
||||||
|
inputMode="numeric"
|
||||||
|
teactExperimentControlled
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ConfirmDialog>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(withGlobal<OwnProps>(
|
||||||
|
(global): Complete<StateProps> => {
|
||||||
|
const { activeGiftAuction } = selectTabState(global);
|
||||||
|
const { stars, currentUserId } = global;
|
||||||
|
|
||||||
|
const currentUserPeer = currentUserId ? selectPeer(global, currentUserId) : undefined;
|
||||||
|
|
||||||
|
const topBidderIds = activeGiftAuction?.state.type === 'active'
|
||||||
|
? activeGiftAuction.state.topBidders
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
auctionState: activeGiftAuction,
|
||||||
|
starBalance: stars?.balance,
|
||||||
|
currentUserPeer,
|
||||||
|
topBidderIds,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
)(GiftAuctionBidModal));
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
import type { OwnProps } from './GiftAuctionChangeRecipientModal';
|
||||||
|
|
||||||
|
import { Bundles } from '../../../../util/moduleLoader';
|
||||||
|
|
||||||
|
import useModuleLoader from '../../../../hooks/useModuleLoader';
|
||||||
|
|
||||||
|
const GiftAuctionChangeRecipientModalAsync = (props: OwnProps) => {
|
||||||
|
const { modal } = props;
|
||||||
|
const GiftAuctionChangeRecipientModal = useModuleLoader(
|
||||||
|
Bundles.Stars,
|
||||||
|
'GiftAuctionChangeRecipientModal',
|
||||||
|
!modal,
|
||||||
|
);
|
||||||
|
|
||||||
|
return GiftAuctionChangeRecipientModal ? <GiftAuctionChangeRecipientModal {...props} /> : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GiftAuctionChangeRecipientModalAsync;
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
.preview {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
font-size: 2rem;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
import { memo } from '../../../../lib/teact/teact';
|
||||||
|
import { getActions, withGlobal } from '../../../../global';
|
||||||
|
|
||||||
|
import type { ApiPeer } from '../../../../api/types';
|
||||||
|
import type { TabState } from '../../../../global/types';
|
||||||
|
|
||||||
|
import { getPeerTitle } from '../../../../global/helpers/peers';
|
||||||
|
import { selectPeer } from '../../../../global/selectors';
|
||||||
|
import { REM } from '../../../common/helpers/mediaDimensions';
|
||||||
|
|
||||||
|
import useCurrentOrPrev from '../../../../hooks/useCurrentOrPrev';
|
||||||
|
import useLang from '../../../../hooks/useLang';
|
||||||
|
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||||
|
|
||||||
|
import Avatar from '../../../common/Avatar';
|
||||||
|
import Icon from '../../../common/icons/Icon';
|
||||||
|
import ConfirmDialog from '../../../ui/ConfirmDialog';
|
||||||
|
|
||||||
|
import styles from './GiftAuctionChangeRecipientModal.module.scss';
|
||||||
|
|
||||||
|
export type OwnProps = {
|
||||||
|
modal: TabState['giftAuctionChangeRecipientModal'];
|
||||||
|
};
|
||||||
|
|
||||||
|
type StateProps = {
|
||||||
|
oldPeer?: ApiPeer;
|
||||||
|
newPeer?: ApiPeer;
|
||||||
|
};
|
||||||
|
|
||||||
|
const AVATAR_SIZE = 4 * REM;
|
||||||
|
|
||||||
|
const GiftAuctionChangeRecipientModal = ({ modal, oldPeer, newPeer }: OwnProps & StateProps) => {
|
||||||
|
const { closeGiftAuctionChangeRecipientModal, openGiftAuctionBidModal } = getActions();
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
|
const isOpen = Boolean(modal?.isOpen);
|
||||||
|
const renderingOldPeer = useCurrentOrPrev(oldPeer);
|
||||||
|
const renderingNewPeer = useCurrentOrPrev(newPeer);
|
||||||
|
const renderingModal = useCurrentOrPrev(modal);
|
||||||
|
|
||||||
|
const handleConfirm = useLastCallback(() => {
|
||||||
|
if (!renderingModal) return;
|
||||||
|
|
||||||
|
closeGiftAuctionChangeRecipientModal();
|
||||||
|
openGiftAuctionBidModal({
|
||||||
|
peerId: renderingModal.newPeerId,
|
||||||
|
message: renderingModal.message,
|
||||||
|
shouldHideName: renderingModal.shouldHideName,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!renderingOldPeer || !renderingNewPeer) return undefined;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConfirmDialog
|
||||||
|
isOpen={isOpen}
|
||||||
|
title={lang('GiftAuctionChangeRecipientTitle')}
|
||||||
|
onClose={closeGiftAuctionChangeRecipientModal}
|
||||||
|
confirmLabel={lang('Continue')}
|
||||||
|
confirmHandler={handleConfirm}
|
||||||
|
>
|
||||||
|
<div className={styles.preview}>
|
||||||
|
<Avatar peer={renderingOldPeer} size={AVATAR_SIZE} />
|
||||||
|
<Icon name="next" className={styles.arrow} />
|
||||||
|
<Avatar peer={renderingNewPeer} size={AVATAR_SIZE} />
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
{lang('GiftAuctionChangeRecipientDescription', {
|
||||||
|
oldPeer: getPeerTitle(lang, renderingOldPeer),
|
||||||
|
newPeer: getPeerTitle(lang, renderingNewPeer),
|
||||||
|
}, {
|
||||||
|
withNodes: true,
|
||||||
|
withMarkdown: true,
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
|
</ConfirmDialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(
|
||||||
|
withGlobal<OwnProps>((global, { modal }): Complete<StateProps> => {
|
||||||
|
const oldPeer = modal?.oldPeerId ? selectPeer(global, modal.oldPeerId) : undefined;
|
||||||
|
const newPeer = modal?.newPeerId ? selectPeer(global, modal.newPeerId) : undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
oldPeer,
|
||||||
|
newPeer,
|
||||||
|
};
|
||||||
|
})(GiftAuctionChangeRecipientModal),
|
||||||
|
);
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
import type { OwnProps } from './GiftAuctionInfoModal';
|
||||||
|
|
||||||
|
import { Bundles } from '../../../../util/moduleLoader';
|
||||||
|
|
||||||
|
import useModuleLoader from '../../../../hooks/useModuleLoader';
|
||||||
|
|
||||||
|
const GiftAuctionInfoModalAsync = (props: OwnProps) => {
|
||||||
|
const { modal } = props;
|
||||||
|
const GiftAuctionInfoModal = useModuleLoader(Bundles.Stars, 'GiftAuctionInfoModal', !modal?.isOpen);
|
||||||
|
|
||||||
|
return GiftAuctionInfoModal ? <GiftAuctionInfoModal {...props} /> : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GiftAuctionInfoModalAsync;
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 0.125rem;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconWrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
width: 5rem;
|
||||||
|
height: 5rem;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
font-size: 1rem;
|
||||||
|
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
color: var(--color-white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
padding-top: 0.25rem;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
padding-top: 0.25rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-self: stretch;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.understoodIcon {
|
||||||
|
font-size: 1.1875rem;
|
||||||
|
}
|
||||||
101
src/components/modals/gift/auction/GiftAuctionInfoModal.tsx
Normal file
101
src/components/modals/gift/auction/GiftAuctionInfoModal.tsx
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import { memo, useMemo } from '../../../../lib/teact/teact';
|
||||||
|
import { getActions, withGlobal } from '../../../../global';
|
||||||
|
|
||||||
|
import type { ApiStarGiftAuctionState } from '../../../../api/types';
|
||||||
|
import type { TabState } from '../../../../global/types';
|
||||||
|
|
||||||
|
import { selectTabState } from '../../../../global/selectors';
|
||||||
|
|
||||||
|
import useLang from '../../../../hooks/useLang';
|
||||||
|
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||||
|
|
||||||
|
import Icon from '../../../common/icons/Icon';
|
||||||
|
import Button from '../../../ui/Button';
|
||||||
|
import TableAboutModal, { type TableAboutData } from '../../common/TableAboutModal';
|
||||||
|
|
||||||
|
import styles from './GiftAuctionInfoModal.module.scss';
|
||||||
|
|
||||||
|
export type OwnProps = {
|
||||||
|
modal: TabState['giftAuctionInfoModal'];
|
||||||
|
};
|
||||||
|
|
||||||
|
type StateProps = {
|
||||||
|
activeGiftAuction?: ApiStarGiftAuctionState;
|
||||||
|
};
|
||||||
|
|
||||||
|
const GiftAuctionInfoModal = ({
|
||||||
|
modal,
|
||||||
|
activeGiftAuction,
|
||||||
|
}: OwnProps & StateProps) => {
|
||||||
|
const { closeGiftAuctionInfoModal } = getActions();
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
|
const isOpen = Boolean(modal?.isOpen && activeGiftAuction);
|
||||||
|
|
||||||
|
const handleClose = useLastCallback(() => {
|
||||||
|
closeGiftAuctionInfoModal();
|
||||||
|
});
|
||||||
|
|
||||||
|
const header = useMemo(() => {
|
||||||
|
return (
|
||||||
|
<div className={styles.header}>
|
||||||
|
<div className={styles.iconWrapper}>
|
||||||
|
<Icon name="auction-filled" className={styles.icon} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.title}>
|
||||||
|
{lang('GiftAuctionInfoTitle')}
|
||||||
|
</div>
|
||||||
|
<div className={styles.subtitle}>
|
||||||
|
{lang('GiftAuctionInfoSubtitle')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}, [lang]);
|
||||||
|
|
||||||
|
const footer = useMemo(() => {
|
||||||
|
if (!isOpen) return undefined;
|
||||||
|
return (
|
||||||
|
<div className={styles.footer}>
|
||||||
|
<Button
|
||||||
|
iconName="understood"
|
||||||
|
iconClassName={styles.understoodIcon}
|
||||||
|
onClick={handleClose}
|
||||||
|
>
|
||||||
|
{lang('ButtonUnderstood')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}, [lang, isOpen, handleClose]);
|
||||||
|
|
||||||
|
const listItemData = useMemo(() => {
|
||||||
|
const count = activeGiftAuction?.gift.giftsPerRound || 0;
|
||||||
|
return [
|
||||||
|
['auction-drop', lang('GiftAuctionInfoTopBiddersTitle', { count }, { pluralValue: count }),
|
||||||
|
lang('GiftAuctionInfoTopBiddersSubtitle', { count }, { pluralValue: count })],
|
||||||
|
['auction-next-round', lang('GiftAuctionInfoBidCarryoverTitle'),
|
||||||
|
lang('GiftAuctionInfoBidCarryoverSubtitle', { count })],
|
||||||
|
['stars-refund', lang('GiftAuctionInfoMissedBiddersTitle'),
|
||||||
|
lang('GiftAuctionInfoMissedBiddersSubtitle')],
|
||||||
|
] satisfies TableAboutData;
|
||||||
|
}, [lang, activeGiftAuction]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableAboutModal
|
||||||
|
isOpen={isOpen}
|
||||||
|
header={header}
|
||||||
|
listItemData={listItemData}
|
||||||
|
footer={footer}
|
||||||
|
onClose={handleClose}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(withGlobal<OwnProps>(
|
||||||
|
(global): Complete<StateProps> => {
|
||||||
|
const { activeGiftAuction } = selectTabState(global);
|
||||||
|
|
||||||
|
return {
|
||||||
|
activeGiftAuction,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
)(GiftAuctionInfoModal));
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
import type { OwnProps } from './GiftAuctionModal';
|
||||||
|
|
||||||
|
import { Bundles } from '../../../../util/moduleLoader';
|
||||||
|
|
||||||
|
import useModuleLoader from '../../../../hooks/useModuleLoader';
|
||||||
|
|
||||||
|
const GiftAuctionModalAsync = (props: OwnProps) => {
|
||||||
|
const { modal } = props;
|
||||||
|
const GiftAuctionModal = useModuleLoader(Bundles.Stars, 'GiftAuctionModal', !modal);
|
||||||
|
|
||||||
|
return GiftAuctionModal ? <GiftAuctionModal {...props} /> : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GiftAuctionModalAsync;
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
.modal :global(.modal-dialog) {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modalContent {
|
||||||
|
position: relative;
|
||||||
|
max-height: min(97vh, 48rem) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
text-wrap: balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin: 0;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
|
line-height: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.finishedBadge {
|
||||||
|
padding: 0.25rem 0.75rem;
|
||||||
|
border-radius: 1rem;
|
||||||
|
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
|
||||||
|
background-color: var(--color-background-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.giftName {
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.75rem;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.itemsBoughtLink {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25rem;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.itemsBoughtSticker {
|
||||||
|
display: inline-flex;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footerButton {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonSubtitle {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-weight: var(--font-weight-normal);
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.starIcon {
|
||||||
|
line-height: 1rem !important;
|
||||||
|
}
|
||||||
220
src/components/modals/gift/auction/GiftAuctionModal.tsx
Normal file
220
src/components/modals/gift/auction/GiftAuctionModal.tsx
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
import { memo, useMemo } from '../../../../lib/teact/teact';
|
||||||
|
import { getActions, withGlobal } from '../../../../global';
|
||||||
|
|
||||||
|
import type { ApiStarGiftAuctionState } from '../../../../api/types';
|
||||||
|
import type { TabState } from '../../../../global/types';
|
||||||
|
|
||||||
|
import { selectTabState } from '../../../../global/selectors';
|
||||||
|
import { formatCountdown, formatDateTimeToString } from '../../../../util/dates/dateFormat';
|
||||||
|
import { HOUR } from '../../../../util/dates/units';
|
||||||
|
import { formatStarsAsIcon } from '../../../../util/localization/format';
|
||||||
|
import { getServerTime } from '../../../../util/serverTime';
|
||||||
|
import { getStickerFromGift } from '../../../common/helpers/gifts';
|
||||||
|
|
||||||
|
import useCurrentOrPrev from '../../../../hooks/useCurrentOrPrev';
|
||||||
|
import useLang from '../../../../hooks/useLang';
|
||||||
|
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||||
|
|
||||||
|
import AnimatedIconFromSticker from '../../../common/AnimatedIconFromSticker';
|
||||||
|
import Button from '../../../ui/Button';
|
||||||
|
import Link from '../../../ui/Link';
|
||||||
|
import TextTimer from '../../../ui/TextTimer';
|
||||||
|
import TableInfoModal, { type TableData } from '../../common/TableInfoModal';
|
||||||
|
import GiftItemStar from '../GiftItemStar';
|
||||||
|
|
||||||
|
import styles from './GiftAuctionModal.module.scss';
|
||||||
|
|
||||||
|
const TEXT_TIMER_THRESHOLD = 48 * HOUR;
|
||||||
|
|
||||||
|
export type OwnProps = {
|
||||||
|
modal: TabState['giftAuctionModal'];
|
||||||
|
};
|
||||||
|
|
||||||
|
type StateProps = {
|
||||||
|
auctionState?: ApiStarGiftAuctionState;
|
||||||
|
};
|
||||||
|
|
||||||
|
const GiftAuctionModal = ({ modal, auctionState }: OwnProps & StateProps) => {
|
||||||
|
const {
|
||||||
|
closeGiftAuctionModal,
|
||||||
|
setGiftModalSelectedGift,
|
||||||
|
openGiftAuctionInfoModal,
|
||||||
|
openGiftAuctionAcquiredModal,
|
||||||
|
} = getActions();
|
||||||
|
|
||||||
|
const isOpen = Boolean(modal?.isOpen);
|
||||||
|
const renderingAuctionState = useCurrentOrPrev(auctionState);
|
||||||
|
|
||||||
|
const gift = renderingAuctionState?.gift;
|
||||||
|
const state = renderingAuctionState?.state;
|
||||||
|
const userState = renderingAuctionState?.userState;
|
||||||
|
const isFinished = state?.type === 'finished';
|
||||||
|
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
|
const handleClose = useLastCallback(() => closeGiftAuctionModal());
|
||||||
|
|
||||||
|
const handleLearnMoreClick = useLastCallback(() => {
|
||||||
|
openGiftAuctionInfoModal({});
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleItemsBoughtClick = useLastCallback(() => {
|
||||||
|
if (!gift) return;
|
||||||
|
const giftSticker = getStickerFromGift(gift);
|
||||||
|
openGiftAuctionAcquiredModal({ giftId: gift.id, giftTitle: gift.title, giftSticker });
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleJoinClick = useLastCallback(() => {
|
||||||
|
if (!gift) return;
|
||||||
|
closeGiftAuctionModal({ shouldKeepActiveAuction: true });
|
||||||
|
setGiftModalSelectedGift({ gift });
|
||||||
|
});
|
||||||
|
|
||||||
|
const header = useMemo(() => {
|
||||||
|
if (!gift || !state) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const giftTitle = gift.title || lang('StarGift');
|
||||||
|
const giftsPerRound = gift.giftsPerRound || 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.header}>
|
||||||
|
<GiftItemStar gift={gift} hideBadge noClickable />
|
||||||
|
<h1 className={styles.title}>
|
||||||
|
{giftTitle}
|
||||||
|
</h1>
|
||||||
|
{isFinished ? (
|
||||||
|
<span className={styles.finishedBadge}>{lang('GiftAuctionEnded')}</span>
|
||||||
|
) : (
|
||||||
|
<p className={styles.description}>
|
||||||
|
{lang('GiftAuctionTopBidders', {
|
||||||
|
count: giftsPerRound,
|
||||||
|
gift: <span className={styles.giftName}>{giftTitle}</span>,
|
||||||
|
link: <Link isPrimary onClick={handleLearnMoreClick}>{lang('GiftAuctionLearnMore')}</Link>,
|
||||||
|
}, { pluralValue: giftsPerRound, withNodes: true, withMarkdown: true })}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}, [gift, state, isFinished, lang, handleLearnMoreClick]);
|
||||||
|
|
||||||
|
const modalData = useMemo(() => {
|
||||||
|
if (!gift || !state || !userState) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableData: TableData = [];
|
||||||
|
|
||||||
|
tableData.push([
|
||||||
|
lang('GiftAuctionStarted'),
|
||||||
|
formatDateTimeToString(state.startDate * 1000, lang.code, true),
|
||||||
|
]);
|
||||||
|
|
||||||
|
tableData.push([
|
||||||
|
lang('GiftAuctionEnds'),
|
||||||
|
formatDateTimeToString(state.endDate * 1000, lang.code, true),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (gift.availabilityTotal) {
|
||||||
|
tableData.push([
|
||||||
|
lang('GiftInfoAvailability'),
|
||||||
|
lang('GiftInfoAvailabilityValue', {
|
||||||
|
count: gift.availabilityRemains || 0,
|
||||||
|
total: lang.number(gift.availabilityTotal),
|
||||||
|
}, { pluralValue: gift.availabilityRemains || 0 }),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.type === 'active') {
|
||||||
|
tableData.push([
|
||||||
|
lang('GiftAuctionCurrentRound'),
|
||||||
|
lang('GiftAuctionRoundValue', {
|
||||||
|
current: lang.number(state.currentRound),
|
||||||
|
total: lang.number(state.totalRounds),
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFinished) {
|
||||||
|
tableData.push([
|
||||||
|
lang('GiftAuctionAveragePrice'),
|
||||||
|
formatStarsAsIcon(lang, state.averagePrice, { className: styles.starIcon }),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const acquiredCount = userState.acquiredCount;
|
||||||
|
const giftSticker = getStickerFromGift(gift);
|
||||||
|
const auctionTimeLeft = state.endDate - getServerTime();
|
||||||
|
const shouldUseTextTimer = auctionTimeLeft > 0 && auctionTimeLeft < TEXT_TIMER_THRESHOLD;
|
||||||
|
|
||||||
|
const footer = (
|
||||||
|
<div className={styles.footer}>
|
||||||
|
{acquiredCount > 0 && (
|
||||||
|
<Link className={styles.itemsBoughtLink} isPrimary onClick={handleItemsBoughtClick}>
|
||||||
|
{lang('GiftAuctionItemsBought', {
|
||||||
|
count: acquiredCount,
|
||||||
|
gift: giftSticker && (
|
||||||
|
<AnimatedIconFromSticker
|
||||||
|
className={styles.itemsBoughtSticker}
|
||||||
|
sticker={giftSticker}
|
||||||
|
size={20}
|
||||||
|
play={false}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}, { pluralValue: acquiredCount, withNodes: true })}
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
noForcedUpperCase
|
||||||
|
className={styles.footerButton}
|
||||||
|
onClick={isFinished ? handleClose : handleJoinClick}
|
||||||
|
>
|
||||||
|
{isFinished ? lang('OK') : (
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
{lang('GiftAuctionJoin')}
|
||||||
|
</div>
|
||||||
|
{auctionTimeLeft > 0 && (
|
||||||
|
<div className={styles.buttonSubtitle}>
|
||||||
|
{lang('GiftAuctionTimeLeft', {
|
||||||
|
time: shouldUseTextTimer
|
||||||
|
? <TextTimer endsAt={state.endDate} />
|
||||||
|
: formatCountdown(lang, auctionTimeLeft),
|
||||||
|
}, { withNodes: true })}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
tableData,
|
||||||
|
footer,
|
||||||
|
};
|
||||||
|
}, [gift, state, userState, isFinished, lang, handleJoinClick, handleItemsBoughtClick, handleClose]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableInfoModal
|
||||||
|
isOpen={isOpen}
|
||||||
|
header={header}
|
||||||
|
footer={modalData?.footer}
|
||||||
|
tableData={modalData?.tableData}
|
||||||
|
className={styles.modal}
|
||||||
|
contentClassName={styles.modalContent}
|
||||||
|
onClose={handleClose}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(withGlobal<OwnProps>(
|
||||||
|
(global): Complete<StateProps> => {
|
||||||
|
const { activeGiftAuction } = selectTabState(global);
|
||||||
|
|
||||||
|
return {
|
||||||
|
auctionState: activeGiftAuction,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
)(GiftAuctionModal));
|
||||||
@ -42,8 +42,8 @@
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.soldOut {
|
.warningDescription {
|
||||||
color: var(--color-error);
|
color: var(--color-error) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modalContent {
|
.modalContent {
|
||||||
@ -51,18 +51,6 @@
|
|||||||
max-height: min(97vh, 48rem) !important;
|
max-height: min(97vh, 48rem) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.headerSplitButton {
|
|
||||||
position: absolute;
|
|
||||||
right: 0.375rem;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
border-radius: 1rem;
|
|
||||||
|
|
||||||
backdrop-filter: blur(0.5rem);
|
|
||||||
}
|
|
||||||
|
|
||||||
.moreMenuButton {
|
.moreMenuButton {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|||||||
@ -440,9 +440,12 @@ const GiftInfoModal = ({
|
|||||||
|
|
||||||
const isVisibleForMe = isNameHidden && renderingTargetPeer;
|
const isVisibleForMe = isNameHidden && renderingTargetPeer;
|
||||||
|
|
||||||
|
const isWarningDescription = savedGift?.isRefunded || (!savedGift && gift?.type === 'starGift');
|
||||||
|
|
||||||
const description = (() => {
|
const description = (() => {
|
||||||
if (!savedGift) return lang('GiftInfoSoldOutDescription');
|
if (!savedGift) return lang('GiftInfoSoldOutDescription');
|
||||||
if (isTargetChat) return undefined;
|
if (isTargetChat) return undefined;
|
||||||
|
if (savedGift.isRefunded) return lang('GiftInfoDescriptionRefunded');
|
||||||
|
|
||||||
if (savedGift.upgradeMsgId) return lang('GiftInfoDescriptionUpgraded');
|
if (savedGift.upgradeMsgId) return lang('GiftInfoDescriptionUpgraded');
|
||||||
if (canManage && savedGift.canUpgrade && savedGift.alreadyPaidUpgradeStars && !savedGift.upgradeMsgId) {
|
if (canManage && savedGift.canUpgrade && savedGift.alreadyPaidUpgradeStars && !savedGift.upgradeMsgId) {
|
||||||
@ -592,7 +595,7 @@ const GiftInfoModal = ({
|
|||||||
{getTitle()}
|
{getTitle()}
|
||||||
</h1>
|
</h1>
|
||||||
{Boolean(description) && (
|
{Boolean(description) && (
|
||||||
<p className={buildClassName(styles.description, !savedGift && gift?.type === 'starGift' && styles.soldOut)}>
|
<p className={buildClassName(styles.description, isWarningDescription && styles.warningDescription)}>
|
||||||
{description}
|
{description}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -5,10 +5,7 @@ import { getActions, withGlobal } from '../../../../global';
|
|||||||
|
|
||||||
import type {
|
import type {
|
||||||
ApiPeer,
|
ApiPeer,
|
||||||
ApiStarGiftAttribute,
|
|
||||||
ApiStarGiftAttributeBackdrop,
|
|
||||||
ApiStarGiftAttributeModel,
|
ApiStarGiftAttributeModel,
|
||||||
ApiStarGiftAttributePattern,
|
|
||||||
} from '../../../../api/types';
|
} from '../../../../api/types';
|
||||||
import type { TabState } from '../../../../global/types';
|
import type { TabState } from '../../../../global/types';
|
||||||
import { ApiMediaFormat } from '../../../../api/types';
|
import { ApiMediaFormat } from '../../../../api/types';
|
||||||
@ -17,6 +14,7 @@ import { getStickerMediaHash } from '../../../../global/helpers';
|
|||||||
import { getPeerTitle } from '../../../../global/helpers/peers';
|
import { getPeerTitle } from '../../../../global/helpers/peers';
|
||||||
import { selectPeer } from '../../../../global/selectors';
|
import { selectPeer } from '../../../../global/selectors';
|
||||||
import { fetch } from '../../../../util/mediaLoader';
|
import { fetch } from '../../../../util/mediaLoader';
|
||||||
|
import { getRandomGiftPreviewAttributes, type GiftPreviewAttributes } from '../../../common/helpers/gifts';
|
||||||
|
|
||||||
import useInterval from '../../../../hooks/schedulers/useInterval';
|
import useInterval from '../../../../hooks/schedulers/useInterval';
|
||||||
import useCurrentOrPrev from '../../../../hooks/useCurrentOrPrev';
|
import useCurrentOrPrev from '../../../../hooks/useCurrentOrPrev';
|
||||||
@ -42,12 +40,6 @@ type StateProps = {
|
|||||||
recipient?: ApiPeer;
|
recipient?: ApiPeer;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Attributes = {
|
|
||||||
model: ApiStarGiftAttributeModel;
|
|
||||||
pattern: ApiStarGiftAttributePattern;
|
|
||||||
backdrop: ApiStarGiftAttributeBackdrop;
|
|
||||||
};
|
|
||||||
|
|
||||||
const PREVIEW_UPDATE_INTERVAL = 3000;
|
const PREVIEW_UPDATE_INTERVAL = 3000;
|
||||||
|
|
||||||
const GiftUpgradeModal = ({ modal, recipient }: OwnProps & StateProps) => {
|
const GiftUpgradeModal = ({ modal, recipient }: OwnProps & StateProps) => {
|
||||||
@ -67,7 +59,7 @@ const GiftUpgradeModal = ({ modal, recipient }: OwnProps & StateProps) => {
|
|||||||
|
|
||||||
const isPrepaid = Boolean(renderingModal?.gift?.prepaidUpgradeHash);
|
const isPrepaid = Boolean(renderingModal?.gift?.prepaidUpgradeHash);
|
||||||
|
|
||||||
const [previewAttributes, setPreviewAttributes] = useState<Attributes | undefined>();
|
const [previewAttributes, setPreviewAttributes] = useState<GiftPreviewAttributes | undefined>();
|
||||||
|
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
|
|
||||||
@ -111,7 +103,7 @@ const GiftUpgradeModal = ({ modal, recipient }: OwnProps & StateProps) => {
|
|||||||
|
|
||||||
const updatePreviewAttributes = useLastCallback(() => {
|
const updatePreviewAttributes = useLastCallback(() => {
|
||||||
if (!renderingModal?.sampleAttributes) return;
|
if (!renderingModal?.sampleAttributes) return;
|
||||||
setPreviewAttributes(getRandomAttributes(renderingModal.sampleAttributes, previewAttributes));
|
setPreviewAttributes(getRandomGiftPreviewAttributes(renderingModal.sampleAttributes, previewAttributes));
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleOpenPriceInfo = useLastCallback(() => {
|
const handleOpenPriceInfo = useLastCallback(() => {
|
||||||
@ -274,25 +266,3 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(GiftUpgradeModal));
|
)(GiftUpgradeModal));
|
||||||
|
|
||||||
function getRandomAttributes(list: ApiStarGiftAttribute[], previousSelection?: Attributes): Attributes {
|
|
||||||
const models = list.filter((attr): attr is ApiStarGiftAttributeModel => (
|
|
||||||
attr.type === 'model' && attr.name !== previousSelection?.model.name
|
|
||||||
));
|
|
||||||
const patterns = list.filter((attr): attr is ApiStarGiftAttributePattern => (
|
|
||||||
attr.type === 'pattern' && attr.name !== previousSelection?.pattern.name
|
|
||||||
));
|
|
||||||
const backdrops = list.filter((attr): attr is ApiStarGiftAttributeBackdrop => (
|
|
||||||
attr.type === 'backdrop' && attr.name !== previousSelection?.backdrop.name
|
|
||||||
));
|
|
||||||
|
|
||||||
const randomModel = models[Math.floor(Math.random() * models.length)];
|
|
||||||
const randomPattern = patterns[Math.floor(Math.random() * patterns.length)];
|
|
||||||
const randomBackdrop = backdrops[Math.floor(Math.random() * backdrops.length)];
|
|
||||||
|
|
||||||
return {
|
|
||||||
model: randomModel,
|
|
||||||
pattern: randomPattern,
|
|
||||||
backdrop: randomBackdrop,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
@use "../../../styles/mixins";
|
@use "../../../styles/mixins";
|
||||||
|
|
||||||
|
/* stylelint-disable plugin/no-low-performance-animation-properties */
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
--_size: 1.875rem;
|
--_size: 1.875rem;
|
||||||
|
--_transition: 0.15s;
|
||||||
--progress: 0;
|
--progress: 0;
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -9,6 +12,24 @@
|
|||||||
padding-top: 4rem;
|
padding-top: 4rem;
|
||||||
|
|
||||||
@include mixins.reset-range();
|
@include mixins.reset-range();
|
||||||
|
|
||||||
|
&.dragging {
|
||||||
|
.progress {
|
||||||
|
transition: background-color var(--_transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.floatingBadgeWrapper {
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.floatingBadgeText {
|
||||||
|
transition: background-color var(--_transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.floatingBadgeTriangle {
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.slider {
|
.slider {
|
||||||
@ -79,6 +100,8 @@
|
|||||||
|
|
||||||
background-image: var(--stars-gradient);
|
background-image: var(--stars-gradient);
|
||||||
|
|
||||||
|
transition: width var(--_transition), background-color var(--_transition);
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
content: "";
|
content: "";
|
||||||
|
|
||||||
@ -93,12 +116,14 @@
|
|||||||
|
|
||||||
background-color: white;
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.dynamicColor {
|
||||||
|
background-color: var(--dynamic-color);
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.floatingBadgeWrapper {
|
.floatingBadgeWrapper {
|
||||||
--_min-x: 0;
|
|
||||||
--_max-x: 100%;
|
|
||||||
|
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -107,11 +132,13 @@
|
|||||||
transform:
|
transform:
|
||||||
translateX(
|
translateX(
|
||||||
clamp(
|
clamp(
|
||||||
var(--_min-x),
|
var(--min-badge-x, 0px),
|
||||||
calc(var(--_size) / 2 + var(--progress) * (100% - var(--_size))),
|
calc(var(--_size) / 2 + var(--progress) * (100% - var(--_size))),
|
||||||
var(--_max-x),
|
var(--max-badge-x, 100%)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
transition: transform var(--_transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
.floatingBadge {
|
.floatingBadge {
|
||||||
@ -121,12 +148,15 @@
|
|||||||
top: -1rem;
|
top: -1rem;
|
||||||
left: 0;
|
left: 0;
|
||||||
transform: translate(-50%, -100%);
|
transform: translate(-50%, -100%);
|
||||||
|
|
||||||
|
&.clickable {
|
||||||
|
pointer-events: auto;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.floatingBadgeText {
|
.floatingBadgeText {
|
||||||
display: flex;
|
position: relative;
|
||||||
gap: 0.125rem;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
border-radius: 2rem;
|
border-radius: 2rem;
|
||||||
@ -138,6 +168,65 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
background-image: var(--stars-gradient);
|
background-image: var(--stars-gradient);
|
||||||
|
|
||||||
|
transition:
|
||||||
|
border-radius var(--_transition),
|
||||||
|
width var(--_transition),
|
||||||
|
background-color var(--_transition);
|
||||||
|
|
||||||
|
&.dynamicColor {
|
||||||
|
background-color: var(--dynamic-color);
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.noTransition {
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.floatingBadgeSparkles {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.floatingBadgeContent {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
height: 1.5rem;
|
||||||
|
|
||||||
|
&.withDescription {
|
||||||
|
.floatingBadgeTitle {
|
||||||
|
transform: translateY(-0.5rem);
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.floatingBadgeDescription {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.floatingBadgeTitle {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.125rem;
|
||||||
|
align-items: center;
|
||||||
|
transition: transform var(--_transition), font-size var(--_transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.floatingBadgeDescription {
|
||||||
|
position: absolute;
|
||||||
|
bottom: -0.125rem;
|
||||||
|
|
||||||
|
font-size: 0.75rem;
|
||||||
|
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
|
transition: opacity var(--_transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
.floatingBadgeTriangle {
|
.floatingBadgeTriangle {
|
||||||
@ -145,5 +234,22 @@
|
|||||||
z-index: -1;
|
z-index: -1;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, 33%);
|
|
||||||
|
transition: transform var(--_transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.floatingBadgeTrianglePath {
|
||||||
|
transition: fill var(--_transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.customValueIcon {
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
right: 0.375rem;
|
||||||
|
bottom: 0.375rem;
|
||||||
|
|
||||||
|
font-size: 1.125rem;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
import type React from '../../../lib/teact/teact';
|
import type { TeactNode } from '../../../lib/teact/teact';
|
||||||
import {
|
import {
|
||||||
memo, useMemo, useRef, useState,
|
memo, useEffect,
|
||||||
} from '../../../lib/teact/teact';
|
useMemo, useRef, useState } from '../../../lib/teact/teact';
|
||||||
|
|
||||||
import { requestMeasure, requestMutation } from '../../../lib/fasterdom/fasterdom';
|
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { formatInteger } from '../../../util/textFormat';
|
import buildStyle from '../../../util/buildStyle';
|
||||||
|
import { REM } from '../../common/helpers/mediaDimensions';
|
||||||
|
|
||||||
import useEffectOnce from '../../../hooks/useEffectOnce';
|
import useLang from '../../../hooks/useLang';
|
||||||
import useLastCallback from '../../../hooks/useLastCallback';
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
|
import usePrevious from '../../../hooks/usePrevious';
|
||||||
import useResizeObserver from '../../../hooks/useResizeObserver';
|
import useResizeObserver from '../../../hooks/useResizeObserver';
|
||||||
|
|
||||||
import AnimatedCounter from '../../common/AnimatedCounter';
|
import AnimatedCounter from '../../common/AnimatedCounter';
|
||||||
@ -20,87 +21,264 @@ import styles from './StarSlider.module.scss';
|
|||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
maxValue: number;
|
maxValue: number;
|
||||||
defaultValue: number;
|
defaultValue: number;
|
||||||
|
minValue?: number;
|
||||||
|
minAllowedValue?: number;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
floatingBadgeDescription?: TeactNode;
|
||||||
|
shouldUseDynamicColor?: boolean;
|
||||||
|
shouldAllowCustomValue?: boolean;
|
||||||
onChange: (value: number) => void;
|
onChange: (value: number) => void;
|
||||||
|
onBadgeClick?: NoneToVoidFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_POINTS = [50, 100, 500, 1000, 2000, 5000, 10000];
|
const DEFAULT_POINTS = [50, 100, 500, 1000, 2000, 5000, 10000];
|
||||||
|
const LARGE_STEP = 10000;
|
||||||
|
const THUMB_SIZE_IN_PIXELS = 1.875 * REM;
|
||||||
|
const BEAK_WIDTH_IN_PIXELS = 28;
|
||||||
|
const DEFAULT_RADIUS_IN_REM = 2;
|
||||||
|
const MIN_RADIUS_IN_REM = 0.375;
|
||||||
|
|
||||||
|
const BADGE_HORIZONTAL_PADDING = 2 * REM;
|
||||||
|
const BADGE_ICON_SIZE = 1.5 * REM;
|
||||||
|
const BADGE_TITLE_GAP = 0.125 * REM;
|
||||||
|
const DRAG_DISTANCE_THRESHOLD = 5;
|
||||||
|
const BADGE_WIDTH_DELTA = 6;
|
||||||
|
|
||||||
|
let textMeasureCanvas: HTMLCanvasElement | undefined;
|
||||||
|
|
||||||
|
function getTextWidth(text: string, font: string): number {
|
||||||
|
if (!textMeasureCanvas) {
|
||||||
|
textMeasureCanvas = document.createElement('canvas');
|
||||||
|
}
|
||||||
|
const ctx = textMeasureCanvas.getContext('2d')!;
|
||||||
|
ctx.font = font;
|
||||||
|
return ctx.measureText(text).width;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SLIDER_COLORS = [
|
||||||
|
'#955CDB', // Purple
|
||||||
|
'#955CDB', // Purple
|
||||||
|
'#46A3EB', // Blue
|
||||||
|
'#40A920', // Green
|
||||||
|
'#E29A09', // Yellow
|
||||||
|
'#ED771E', // Orange
|
||||||
|
'#E14542', // Red
|
||||||
|
'#596473', // Silver (100% only)
|
||||||
|
];
|
||||||
|
|
||||||
|
function getColorForProgress(progress: number): string {
|
||||||
|
if (progress >= 1) return SLIDER_COLORS[SLIDER_COLORS.length - 1];
|
||||||
|
|
||||||
|
const regularColorsCount = SLIDER_COLORS.length - 1;
|
||||||
|
const index = Math.floor(progress * regularColorsCount);
|
||||||
|
return SLIDER_COLORS[Math.min(index, regularColorsCount - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
const StarSlider = ({
|
const StarSlider = ({
|
||||||
maxValue,
|
maxValue,
|
||||||
defaultValue,
|
defaultValue,
|
||||||
|
minValue,
|
||||||
|
minAllowedValue,
|
||||||
className,
|
className,
|
||||||
|
floatingBadgeDescription,
|
||||||
|
shouldUseDynamicColor,
|
||||||
|
shouldAllowCustomValue,
|
||||||
onChange,
|
onChange,
|
||||||
|
onBadgeClick,
|
||||||
}: OwnProps) => {
|
}: OwnProps) => {
|
||||||
const floatingBadgeRef = useRef<HTMLDivElement>();
|
const containerRef = useRef<HTMLDivElement>();
|
||||||
|
const floatingBadgeContentRef = useRef<HTMLDivElement>();
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
|
const min = minValue ?? 1;
|
||||||
|
|
||||||
const points = useMemo(() => {
|
const points = useMemo(() => {
|
||||||
const result = [];
|
const result = [];
|
||||||
|
|
||||||
for (let i = 0; i < DEFAULT_POINTS.length; i++) {
|
for (let i = 0; i < DEFAULT_POINTS.length; i++) {
|
||||||
|
if (DEFAULT_POINTS[i] <= min) continue;
|
||||||
|
|
||||||
if (DEFAULT_POINTS[i] < maxValue) {
|
if (DEFAULT_POINTS[i] < maxValue) {
|
||||||
result.push(DEFAULT_POINTS[i]);
|
result.push(DEFAULT_POINTS[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DEFAULT_POINTS[i] >= maxValue) {
|
if (DEFAULT_POINTS[i] >= maxValue) {
|
||||||
result.push(maxValue);
|
result.push(maxValue);
|
||||||
break;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const lastPoint = DEFAULT_POINTS[DEFAULT_POINTS.length - 1];
|
||||||
|
let nextPoint = lastPoint + LARGE_STEP;
|
||||||
|
while (nextPoint < maxValue) {
|
||||||
|
result.push(nextPoint);
|
||||||
|
nextPoint += LARGE_STEP;
|
||||||
|
}
|
||||||
|
result.push(maxValue);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}, [maxValue]);
|
}, [maxValue, min]);
|
||||||
|
|
||||||
const [value, setValue] = useState(0);
|
const [value, setValue] = useState(0);
|
||||||
|
const [containerWidth, setContainerWidth] = useState(0);
|
||||||
|
const [badgeWidth, setBadgeWidth] = useState(0);
|
||||||
|
const [isDragging, setIsDragging] = useState(false);
|
||||||
|
const startXRef = useRef<number | undefined>();
|
||||||
|
const prevBadgeWidth = usePrevious(badgeWidth);
|
||||||
|
|
||||||
useEffectOnce(() => {
|
const badgeText = lang.number(getValue(points, value, min));
|
||||||
setValue(getProgress(points, defaultValue));
|
|
||||||
});
|
|
||||||
|
|
||||||
const updateSafeBadgePosition = useLastCallback(() => {
|
const minAllowedProgress = minAllowedValue !== undefined
|
||||||
const badge = floatingBadgeRef.current;
|
? getProgress(points, minAllowedValue, min) : 0;
|
||||||
if (!badge) return;
|
|
||||||
const parent = badge.parentElement!;
|
|
||||||
|
|
||||||
requestMeasure(() => {
|
useEffect(() => {
|
||||||
const safeMinX = parent.offsetLeft + badge.offsetWidth / 2;
|
setValue(getProgress(points, defaultValue, min));
|
||||||
const safeMaxX = parent.offsetLeft + parent.offsetWidth - badge.offsetWidth / 2;
|
}, [defaultValue, points, min]);
|
||||||
|
|
||||||
requestMutation(() => {
|
useEffect(() => {
|
||||||
parent.style.setProperty('--_min-x', `${safeMinX}px`);
|
if (!floatingBadgeContentRef.current) return;
|
||||||
parent.style.setProperty('--_max-x', `${safeMaxX}px`);
|
|
||||||
});
|
const titleEl = floatingBadgeContentRef.current.querySelector(`.${styles.floatingBadgeTitle}`);
|
||||||
|
if (!titleEl) return;
|
||||||
|
|
||||||
|
const computedStyle = getComputedStyle(titleEl);
|
||||||
|
const font = `${computedStyle.fontWeight} ${computedStyle.fontSize} ${computedStyle.fontFamily}`;
|
||||||
|
|
||||||
|
const textWidth = getTextWidth(badgeText, font);
|
||||||
|
const titleWidth = BADGE_ICON_SIZE + BADGE_TITLE_GAP + textWidth;
|
||||||
|
|
||||||
|
const descriptionEl = floatingBadgeContentRef.current.querySelector(`.${styles.floatingBadgeDescription}`);
|
||||||
|
const descriptionWidth = descriptionEl?.scrollWidth || 0;
|
||||||
|
|
||||||
|
const contentWidth = Math.max(titleWidth, descriptionWidth);
|
||||||
|
const newBadgeWidth = contentWidth + BADGE_HORIZONTAL_PADDING;
|
||||||
|
|
||||||
|
setBadgeWidth((currentWidth) => {
|
||||||
|
if (Math.abs(newBadgeWidth - currentWidth) < BADGE_WIDTH_DELTA) {
|
||||||
|
return currentWidth;
|
||||||
|
}
|
||||||
|
return newBadgeWidth;
|
||||||
});
|
});
|
||||||
|
}, [badgeText, floatingBadgeDescription]);
|
||||||
|
|
||||||
|
const handleContainerResize = useLastCallback((entry: ResizeObserverEntry) => {
|
||||||
|
setContainerWidth(entry.contentRect.width);
|
||||||
});
|
});
|
||||||
|
|
||||||
useResizeObserver(floatingBadgeRef, updateSafeBadgePosition);
|
useResizeObserver(containerRef, handleContainerResize);
|
||||||
|
|
||||||
|
const progress = value / points.length;
|
||||||
|
const {
|
||||||
|
minBadgeX, maxBadgeX, beakOffset, cornerRadius,
|
||||||
|
} = useMemo(() => {
|
||||||
|
return calcBadgePosition(containerWidth, badgeWidth, progress);
|
||||||
|
}, [containerWidth, badgeWidth, progress]);
|
||||||
|
|
||||||
const handleChange = useLastCallback((event: React.ChangeEvent<HTMLInputElement>) => {
|
const handleChange = useLastCallback((event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const newValue = Number(event.currentTarget.value);
|
const rawValue = Number(event.currentTarget.value);
|
||||||
setValue(newValue);
|
const clampedValue = Math.max(rawValue, minAllowedProgress);
|
||||||
|
setValue(clampedValue);
|
||||||
|
|
||||||
onChange(getValue(points, newValue));
|
const resultValue = getValue(points, clampedValue, min);
|
||||||
|
onChange(resultValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handlePointerDown = useLastCallback((e: React.PointerEvent<HTMLInputElement>) => {
|
||||||
|
startXRef.current = e.clientX;
|
||||||
|
setIsDragging(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
const handlePointerMove = useLastCallback((e: React.PointerEvent<HTMLInputElement>) => {
|
||||||
|
if (startXRef.current === undefined) return;
|
||||||
|
const distance = Math.abs(e.clientX - startXRef.current);
|
||||||
|
if (distance >= DRAG_DISTANCE_THRESHOLD) {
|
||||||
|
setIsDragging(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const handlePointerUp = useLastCallback(() => {
|
||||||
|
startXRef.current = undefined;
|
||||||
|
setIsDragging(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
const { left: radiusLeft, right: radiusRight } = cornerRadius;
|
||||||
|
const dynamicColor = shouldUseDynamicColor ? getColorForProgress(progress) : undefined;
|
||||||
|
|
||||||
|
const badgeStyle = buildStyle(
|
||||||
|
`border-radius: 2rem 2rem ${radiusRight}rem ${radiusLeft}rem`,
|
||||||
|
Boolean(badgeWidth) && `width: ${badgeWidth}px`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const rootStyle = buildStyle(
|
||||||
|
`--progress: ${progress}`,
|
||||||
|
`--min-badge-x: ${minBadgeX}px`,
|
||||||
|
`--max-badge-x: ${maxBadgeX}px`,
|
||||||
|
dynamicColor && `--dynamic-color: ${dynamicColor}`,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={buildClassName(styles.root, className)} style={`--progress: ${value / points.length}`}>
|
<div
|
||||||
|
ref={containerRef}
|
||||||
|
className={buildClassName(styles.root, isDragging && styles.dragging, className)}
|
||||||
|
style={rootStyle}
|
||||||
|
>
|
||||||
<div className={styles.floatingBadgeWrapper}>
|
<div className={styles.floatingBadgeWrapper}>
|
||||||
<div className={styles.floatingBadge} ref={floatingBadgeRef}>
|
<div
|
||||||
<div className={styles.floatingBadgeText}>
|
className={buildClassName(styles.floatingBadge, onBadgeClick && styles.clickable)}
|
||||||
<Icon name="star" className={styles.floatingBadgeIcon} />
|
onClick={onBadgeClick}
|
||||||
<AnimatedCounter text={formatInteger(getValue(points, value))} />
|
>
|
||||||
|
<div
|
||||||
|
className={buildClassName(
|
||||||
|
styles.floatingBadgeText,
|
||||||
|
shouldUseDynamicColor && styles.dynamicColor,
|
||||||
|
(!prevBadgeWidth || prevBadgeWidth === 0) && styles.noTransition,
|
||||||
|
)}
|
||||||
|
style={badgeStyle}
|
||||||
|
>
|
||||||
|
<Sparkles preset="button" className={styles.floatingBadgeSparkles} />
|
||||||
|
<div
|
||||||
|
ref={floatingBadgeContentRef}
|
||||||
|
className={buildClassName(
|
||||||
|
styles.floatingBadgeContent,
|
||||||
|
floatingBadgeDescription && styles.withDescription,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className={styles.floatingBadgeTitle}>
|
||||||
|
<Icon name="star" className={styles.floatingBadgeIcon} />
|
||||||
|
<AnimatedCounter text={badgeText} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.floatingBadgeDescription}>
|
||||||
|
{floatingBadgeDescription}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<svg className={styles.floatingBadgeTriangle} width="28" height="28" viewBox="0 0 28 28" fill="none">
|
<svg
|
||||||
<defs>
|
className={styles.floatingBadgeTriangle}
|
||||||
<linearGradient id="StarBadgeTriangle" x1="0" x2="1" y1="0" y2="0">
|
width="28"
|
||||||
<stop offset="-50%" stop-color="#FFAA00" />
|
height="28"
|
||||||
<stop offset="150%" stop-color="#FFCD3A" />
|
viewBox="0 0 28 28"
|
||||||
</linearGradient>
|
fill="none"
|
||||||
</defs>
|
aria-hidden="true"
|
||||||
<path d="m 28,4 v 9 c 0.0089,7.283278 -3.302215,5.319646 -6.750951,8.589815 l -5.8284,5.82843 c -0.781,0.78105 -2.0474,0.78104 -2.8284,0 L 6.7638083,21.589815 C 2.8288652,17.959047 0.04527024,20.332086 0,13 V 4 C 0,4 0.00150581,0.97697493 3,1 5.3786658,1.018266 22.594519,0.9142007 25,1 c 2.992326,0.1067311 3,3 3,3 z" fill="url(#StarBadgeTriangle)" />
|
role="presentation"
|
||||||
|
style={`transform: translate(calc(-50% + ${beakOffset}px), 33%)`}
|
||||||
|
>
|
||||||
|
{!shouldUseDynamicColor && (
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="StarBadgeTriangle" x1="0" x2="1" y1="0" y2="0">
|
||||||
|
<stop offset="-50%" stop-color="#FFAA00" />
|
||||||
|
<stop offset="150%" stop-color="#FFCD3A" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
)}
|
||||||
|
<path
|
||||||
|
className={styles.floatingBadgeTrianglePath}
|
||||||
|
d="m 28,4 v 9 c 0.0089,7.283278 -3.302215,5.319646 -6.750951,8.589815 l -5.8284,5.82843 c -0.781,0.78105 -2.0474,0.78104 -2.8284,0 L 6.7638083,21.589815 C 2.8288652,17.959047 0.04527024,20.332086 0,13 V 4 C 0,4 0.00150581,0.97697493 3,1 5.3786658,1.018266 22.594519,0.9142007 25,1 c 2.992326,0.1067311 3,3 3,3 z"
|
||||||
|
fill={dynamicColor || 'url(#StarBadgeTriangle)'}
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.progress}>
|
<div className={buildClassName(styles.progress, shouldUseDynamicColor && styles.dynamicColor)}>
|
||||||
<Sparkles preset="progress" className={styles.sparkles} />
|
<Sparkles preset="progress" className={styles.sparkles} />
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
@ -108,28 +286,82 @@ const StarSlider = ({
|
|||||||
type="range"
|
type="range"
|
||||||
min={0}
|
min={0}
|
||||||
max={points.length}
|
max={points.length}
|
||||||
defaultValue={getProgress(points, defaultValue)}
|
defaultValue={getProgress(points, defaultValue, min)}
|
||||||
step="any"
|
step="any"
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
onPointerDown={handlePointerDown}
|
||||||
|
onPointerMove={handlePointerMove}
|
||||||
|
onPointerUp={handlePointerUp}
|
||||||
/>
|
/>
|
||||||
|
{shouldAllowCustomValue && (
|
||||||
|
<Icon name="add" className={styles.customValueIcon} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function getProgress(points: number[], value: number) {
|
function getProgress(points: number[], value: number, minValue: number) {
|
||||||
const pointIndex = points.findIndex((point) => value <= point);
|
const pointIndex = points.findIndex((point) => value <= point);
|
||||||
const prevPoint = points[pointIndex - 1] || 1;
|
const prevPoint = points[pointIndex - 1] || minValue;
|
||||||
const nextPoint = points[pointIndex] || points[points.length - 1];
|
const nextPoint = points[pointIndex] || points[points.length - 1];
|
||||||
|
if (nextPoint === prevPoint) return pointIndex;
|
||||||
const progress = (value - prevPoint) / (nextPoint - prevPoint);
|
const progress = (value - prevPoint) / (nextPoint - prevPoint);
|
||||||
return pointIndex + progress;
|
return pointIndex + progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getValue(points: number[], progress: number) {
|
function getValue(points: number[], progress: number, minValue: number) {
|
||||||
const pointIndex = Math.floor(progress);
|
const pointIndex = Math.floor(progress);
|
||||||
const prevPoint = points[pointIndex - 1] || 1;
|
const prevPoint = points[pointIndex - 1] || minValue;
|
||||||
const nextPoint = points[pointIndex] || points[points.length - 1];
|
const nextPoint = points[pointIndex] || points[points.length - 1];
|
||||||
const value = prevPoint + (nextPoint - prevPoint) * (progress - pointIndex);
|
const value = prevPoint + (nextPoint - prevPoint) * (progress - pointIndex);
|
||||||
return Math.round(value);
|
return Math.round(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function calcBadgePosition(
|
||||||
|
containerWidth: number,
|
||||||
|
badgeWidth: number,
|
||||||
|
progress: number,
|
||||||
|
) {
|
||||||
|
const halfBadgeWidth = badgeWidth / 2;
|
||||||
|
const halfThumbSize = THUMB_SIZE_IN_PIXELS / 2;
|
||||||
|
|
||||||
|
const baseTargetX = halfThumbSize + progress * (containerWidth - THUMB_SIZE_IN_PIXELS);
|
||||||
|
const cornerTargetX = progress * containerWidth;
|
||||||
|
|
||||||
|
const edgeZone = THUMB_SIZE_IN_PIXELS / 2;
|
||||||
|
const distanceToLeftEdge = cornerTargetX;
|
||||||
|
const distanceToRightEdge = containerWidth - cornerTargetX;
|
||||||
|
const minEdgeDistance = Math.min(distanceToLeftEdge, distanceToRightEdge);
|
||||||
|
|
||||||
|
const t = Math.min(1, minEdgeDistance / edgeZone);
|
||||||
|
const targetX = cornerTargetX + t * (baseTargetX - cornerTargetX);
|
||||||
|
const minBadgeX = halfBadgeWidth;
|
||||||
|
const maxBadgeX = containerWidth - halfBadgeWidth;
|
||||||
|
const clampedBadgeX = Math.max(minBadgeX, Math.min(targetX, maxBadgeX));
|
||||||
|
|
||||||
|
const beakOffset = targetX - clampedBadgeX;
|
||||||
|
|
||||||
|
const thresholdPx = DEFAULT_RADIUS_IN_REM / 2 * REM;
|
||||||
|
const beakHalfWidth = BEAK_WIDTH_IN_PIXELS / 2;
|
||||||
|
|
||||||
|
const distanceToEdge = halfBadgeWidth - Math.abs(beakOffset);
|
||||||
|
const normalizedDistance = Math.max(0, distanceToEdge - beakHalfWidth);
|
||||||
|
|
||||||
|
let edgeRadius = DEFAULT_RADIUS_IN_REM;
|
||||||
|
if (normalizedDistance < thresholdPx) {
|
||||||
|
const radiusT = 1 - (normalizedDistance / thresholdPx);
|
||||||
|
edgeRadius = DEFAULT_RADIUS_IN_REM - radiusT * (DEFAULT_RADIUS_IN_REM - MIN_RADIUS_IN_REM);
|
||||||
|
}
|
||||||
|
|
||||||
|
const leftRadius = beakOffset < 0 ? edgeRadius : DEFAULT_RADIUS_IN_REM;
|
||||||
|
const rightRadius = beakOffset > 0 ? edgeRadius : DEFAULT_RADIUS_IN_REM;
|
||||||
|
|
||||||
|
return {
|
||||||
|
minBadgeX,
|
||||||
|
maxBadgeX,
|
||||||
|
beakOffset,
|
||||||
|
cornerRadius: { left: leftRadius, right: rightRadius },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export default memo(StarSlider);
|
export default memo(StarSlider);
|
||||||
|
|||||||
@ -37,6 +37,12 @@ export function getTransactionTitle(oldLang: OldLangFn, lang: LangFn, transactio
|
|||||||
return lang('GiftPrepaidUpgradeTransactionTitle');
|
return lang('GiftPrepaidUpgradeTransactionTitle');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (transaction.isStarGiftAuctionBid) {
|
||||||
|
return isNegativeAmount(transaction.amount)
|
||||||
|
? lang('StarGiftAuctionBidTransaction')
|
||||||
|
: lang('StarGiftAuctionBidRefundedTransaction');
|
||||||
|
}
|
||||||
|
|
||||||
if (transaction.starRefCommision) {
|
if (transaction.starRefCommision) {
|
||||||
return oldLang('StarTransactionCommission', formatPercent(transaction.starRefCommision));
|
return oldLang('StarTransactionCommission', formatPercent(transaction.starRefCommision));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -260,7 +260,7 @@ const StarsTransactionModal: FC<OwnProps & StateProps> = ({
|
|||||||
peerLabel = oldLang('Stars.Transaction.Via');
|
peerLabel = oldLang('Stars.Transaction.Via');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!transaction.isPostsSearch && !isDropOriginalDetails) {
|
if (!transaction.isPostsSearch && !isDropOriginalDetails && !transaction.isStarGiftAuctionBid) {
|
||||||
tableData.push([
|
tableData.push([
|
||||||
peerLabel,
|
peerLabel,
|
||||||
peerId ? { chatId: peerId } : toName || '',
|
peerId ? { chatId: peerId } : toName || '',
|
||||||
@ -312,6 +312,18 @@ const StarsTransactionModal: FC<OwnProps & StateProps> = ({
|
|||||||
formatDateTimeToString(transaction.date * 1000, oldLang.code, true),
|
formatDateTimeToString(transaction.date * 1000, oldLang.code, true),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if (transaction.isStarGiftAuctionBid && gift?.type === 'starGift' && gift.availabilityTotal) {
|
||||||
|
tableData.push([
|
||||||
|
lang('GiftInfoAvailability'),
|
||||||
|
lang('GiftInfoAvailabilityValue', {
|
||||||
|
count: gift.availabilityRemains || 0,
|
||||||
|
total: gift.availabilityTotal,
|
||||||
|
}, {
|
||||||
|
pluralValue: gift.availabilityRemains || 0,
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
const footerText = oldLang('lng_credits_box_out_about');
|
const footerText = oldLang('lng_credits_box_out_about');
|
||||||
const footerTextParts = footerText.split('{link}');
|
const footerTextParts = footerText.split('{link}');
|
||||||
|
|
||||||
|
|||||||
@ -10,12 +10,13 @@ import AnimatedCounter from '../common/AnimatedCounter';
|
|||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
endsAt: number;
|
endsAt: number;
|
||||||
|
shouldShowZeroOnEnd?: boolean;
|
||||||
onEnd?: NoneToVoidFunction;
|
onEnd?: NoneToVoidFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
const UPDATE_FREQUENCY = 500; // Sometimes second gets skipped if using 1000
|
const UPDATE_FREQUENCY = 500; // Sometimes second gets skipped if using 1000
|
||||||
|
|
||||||
const TextTimer = ({ endsAt, onEnd }: OwnProps) => {
|
const TextTimer = ({ endsAt, shouldShowZeroOnEnd, onEnd }: OwnProps) => {
|
||||||
const forceUpdate = useForceUpdate();
|
const forceUpdate = useForceUpdate();
|
||||||
|
|
||||||
const serverTime = getServerTime();
|
const serverTime = getServerTime();
|
||||||
@ -28,9 +29,9 @@ const TextTimer = ({ endsAt, onEnd }: OwnProps) => {
|
|||||||
}
|
}
|
||||||
}, [isActive, onEnd]);
|
}, [isActive, onEnd]);
|
||||||
|
|
||||||
if (!isActive) return undefined;
|
if (!isActive && !shouldShowZeroOnEnd) return undefined;
|
||||||
|
|
||||||
const timeLeft = endsAt - serverTime;
|
const timeLeft = Math.max(0, endsAt - serverTime);
|
||||||
const time = formatMediaDuration(timeLeft);
|
const time = formatMediaDuration(timeLeft);
|
||||||
|
|
||||||
const timeParts = time.split(':');
|
const timeParts = time.split(':');
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import type {
|
import type {
|
||||||
ApiInputInvoice, ApiInputInvoicePremiumGiftStars, ApiInputInvoiceStarGift, ApiInputInvoiceStarGiftResale,
|
ApiInputInvoice, ApiInputInvoicePremiumGiftStars, ApiInputInvoiceStarGift,
|
||||||
|
ApiInputInvoiceStarGiftAuctionBid, ApiInputInvoiceStarGiftResale,
|
||||||
ApiRequestInputInvoice,
|
ApiRequestInputInvoice,
|
||||||
} from '../../../api/types';
|
} from '../../../api/types';
|
||||||
import type { ApiCredentials } from '../../../components/payment/PaymentModal';
|
import type { ApiCredentials } from '../../../components/payment/PaymentModal';
|
||||||
@ -575,7 +576,7 @@ addActionHandler('checkCanSendGift', async (global, actions, payload): Promise<v
|
|||||||
|
|
||||||
addActionHandler('openGiftModal', async (global, actions, payload): Promise<void> => {
|
addActionHandler('openGiftModal', async (global, actions, payload): Promise<void> => {
|
||||||
const {
|
const {
|
||||||
forUserId, selectedResaleGift, tabId = getCurrentTabId(),
|
forUserId, selectedGift, selectedResaleGift, tabId = getCurrentTabId(),
|
||||||
} = payload;
|
} = payload;
|
||||||
|
|
||||||
if (selectIsCurrentUserFrozen(global)) {
|
if (selectIsCurrentUserFrozen(global)) {
|
||||||
@ -592,6 +593,7 @@ addActionHandler('openGiftModal', async (global, actions, payload): Promise<void
|
|||||||
forPeerId: forUserId,
|
forPeerId: forUserId,
|
||||||
gifts,
|
gifts,
|
||||||
selectedResaleGift,
|
selectedResaleGift,
|
||||||
|
selectedGift,
|
||||||
},
|
},
|
||||||
}, tabId);
|
}, tabId);
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
@ -1140,6 +1142,24 @@ addActionHandler('upgradePrepaidGift', (global, actions, payload): ActionReturnT
|
|||||||
payInputStarInvoice(global, invoice, stars, tabId);
|
payInputStarInvoice(global, invoice, stars, tabId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addActionHandler('sendStarGiftAuctionBid', (global, actions, payload): ActionReturnType => {
|
||||||
|
const {
|
||||||
|
giftId, bidAmount, peerId, message, shouldHideName, isUpdateBid, tabId = getCurrentTabId(),
|
||||||
|
} = payload;
|
||||||
|
|
||||||
|
const invoice: ApiInputInvoiceStarGiftAuctionBid = {
|
||||||
|
type: 'stargiftAuctionBid',
|
||||||
|
giftId,
|
||||||
|
bidAmount,
|
||||||
|
peerId,
|
||||||
|
message,
|
||||||
|
shouldHideName,
|
||||||
|
isUpdateBid,
|
||||||
|
};
|
||||||
|
|
||||||
|
payInputStarInvoice(global, invoice, bidAmount, tabId);
|
||||||
|
});
|
||||||
|
|
||||||
async function payInputStarInvoice<T extends GlobalState>(
|
async function payInputStarInvoice<T extends GlobalState>(
|
||||||
global: T, inputInvoice: ApiInputInvoice, price: number,
|
global: T, inputInvoice: ApiInputInvoice, price: number,
|
||||||
...[tabId = getCurrentTabId()]: TabArgs<T>
|
...[tabId = getCurrentTabId()]: TabArgs<T>
|
||||||
@ -1229,6 +1249,26 @@ addActionHandler('openUniqueGiftBySlug', async (global, actions, payload): Promi
|
|||||||
actions.openGiftInfoModal({ gift, tabId });
|
actions.openGiftInfoModal({ gift, tabId });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addActionHandler('openGiftAuctionBySlug', async (global, actions, payload): Promise<void> => {
|
||||||
|
const {
|
||||||
|
slug, tabId = getCurrentTabId(),
|
||||||
|
} = payload;
|
||||||
|
|
||||||
|
const auctionState = await callApi('fetchStarGiftAuctionState', { slug });
|
||||||
|
|
||||||
|
if (!auctionState) {
|
||||||
|
actions.showNotification({
|
||||||
|
message: {
|
||||||
|
key: 'GiftWasNotFound',
|
||||||
|
},
|
||||||
|
tabId,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
actions.openGiftAuctionModal({ gift: auctionState.gift, tabId });
|
||||||
|
});
|
||||||
|
|
||||||
addActionHandler('processStarGiftWithdrawal', async (global, actions, payload): Promise<void> => {
|
addActionHandler('processStarGiftWithdrawal', async (global, actions, payload): Promise<void> => {
|
||||||
const {
|
const {
|
||||||
gift, password, tabId = getCurrentTabId(),
|
gift, password, tabId = getCurrentTabId(),
|
||||||
|
|||||||
@ -12,11 +12,12 @@ import { getServerTime } from '../../../util/serverTime';
|
|||||||
import { callApi } from '../../../api/gramjs';
|
import { callApi } from '../../../api/gramjs';
|
||||||
import { RESALE_GIFTS_LIMIT } from '../../../limits';
|
import { RESALE_GIFTS_LIMIT } from '../../../limits';
|
||||||
import { areInputSavedGiftsEqual, getRequestInputSavedStarGift } from '../../helpers/payments';
|
import { areInputSavedGiftsEqual, getRequestInputSavedStarGift } from '../../helpers/payments';
|
||||||
import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
import { addActionHandler, getGlobal, getPromiseActions, setGlobal } from '../../index';
|
||||||
import {
|
import {
|
||||||
appendStarsSubscriptions,
|
appendStarsSubscriptions,
|
||||||
appendStarsTransactions,
|
appendStarsTransactions,
|
||||||
replacePeerSavedGifts,
|
replacePeerSavedGifts,
|
||||||
|
updateActiveGiftAuction,
|
||||||
updateChats,
|
updateChats,
|
||||||
updatePeerStarGiftCollections,
|
updatePeerStarGiftCollections,
|
||||||
updateStarsBalance,
|
updateStarsBalance,
|
||||||
@ -579,6 +580,43 @@ addActionHandler('shiftGiftUpgradeNextPrice', async (global, _actions, payload):
|
|||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addActionHandler('openGiftAuctionModal', async (global, _actions, payload): Promise<void> => {
|
||||||
|
const { gift, tabId = getCurrentTabId() } = payload;
|
||||||
|
|
||||||
|
await getPromiseActions().loadActiveGiftAuction({ giftId: gift.id, tabId });
|
||||||
|
|
||||||
|
global = getGlobal();
|
||||||
|
global = updateTabState(global, {
|
||||||
|
giftAuctionModal: { isOpen: true },
|
||||||
|
}, tabId);
|
||||||
|
setGlobal(global);
|
||||||
|
});
|
||||||
|
|
||||||
|
addActionHandler('loadActiveGiftAuction', async (global, _actions, payload): Promise<void> => {
|
||||||
|
const { giftId, tabId = getCurrentTabId() } = payload;
|
||||||
|
|
||||||
|
const currentAuction = selectTabState(global, tabId).activeGiftAuction;
|
||||||
|
const currentVersion = currentAuction?.state.type === 'active' ? currentAuction.state.version : 0;
|
||||||
|
|
||||||
|
const auctionState = await callApi('fetchStarGiftAuctionState', {
|
||||||
|
giftId,
|
||||||
|
version: currentVersion,
|
||||||
|
});
|
||||||
|
if (!auctionState) return;
|
||||||
|
|
||||||
|
global = getGlobal();
|
||||||
|
global = updateActiveGiftAuction(global, auctionState, tabId);
|
||||||
|
setGlobal(global);
|
||||||
|
});
|
||||||
|
|
||||||
|
addActionHandler('clearActiveGiftAuction', (global, _actions, payload): ActionReturnType => {
|
||||||
|
const { tabId = getCurrentTabId() } = payload || {};
|
||||||
|
|
||||||
|
return updateTabState(global, {
|
||||||
|
activeGiftAuction: undefined,
|
||||||
|
}, tabId);
|
||||||
|
});
|
||||||
|
|
||||||
addActionHandler('toggleSavedGiftPinned', async (global, actions, payload): Promise<void> => {
|
addActionHandler('toggleSavedGiftPinned', async (global, actions, payload): Promise<void> => {
|
||||||
const { gift, peerId, tabId = getCurrentTabId() } = payload;
|
const { gift, peerId, tabId = getCurrentTabId() } = payload;
|
||||||
|
|
||||||
@ -650,3 +688,26 @@ addActionHandler('loadStarGiftCollections', async (global, actions, payload): Pr
|
|||||||
global = updatePeerStarGiftCollections(global, peerId, result.collections);
|
global = updatePeerStarGiftCollections(global, peerId, result.collections);
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addActionHandler('openGiftAuctionAcquiredModal', async (global, actions, payload): Promise<void> => {
|
||||||
|
const {
|
||||||
|
giftId, giftTitle, giftSticker, tabId = getCurrentTabId(),
|
||||||
|
} = payload;
|
||||||
|
|
||||||
|
const result = await callApi('fetchStarGiftAuctionAcquiredGifts', { giftId });
|
||||||
|
|
||||||
|
if (!result) return;
|
||||||
|
|
||||||
|
global = getGlobal();
|
||||||
|
|
||||||
|
global = updateTabState(global, {
|
||||||
|
giftAuctionAcquiredModal: {
|
||||||
|
giftId,
|
||||||
|
giftTitle,
|
||||||
|
giftSticker,
|
||||||
|
acquiredGifts: result.gifts,
|
||||||
|
},
|
||||||
|
}, tabId);
|
||||||
|
|
||||||
|
setGlobal(global);
|
||||||
|
});
|
||||||
|
|||||||
@ -240,6 +240,40 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
|||||||
|
|
||||||
case 'newMessage': {
|
case 'newMessage': {
|
||||||
const action = update.message.content?.action;
|
const action = update.message.content?.action;
|
||||||
|
|
||||||
|
if (action?.type === 'starGift' && update.message.isOutgoing) {
|
||||||
|
const { gift } = action;
|
||||||
|
if (!gift.isAuction || update.message.chatId === SERVICE_NOTIFICATIONS_USER_ID) return undefined;
|
||||||
|
|
||||||
|
const { chatId, id } = update.message;
|
||||||
|
|
||||||
|
if (!chatId || !id) return;
|
||||||
|
|
||||||
|
Object.values(global.byTabId).forEach(({ id: tabId }) => {
|
||||||
|
actions.focusMessage({
|
||||||
|
chatId,
|
||||||
|
messageId: id,
|
||||||
|
tabId,
|
||||||
|
});
|
||||||
|
actions.closeGiftAuctionBidModal({ tabId });
|
||||||
|
actions.closeGiftModal({ tabId });
|
||||||
|
|
||||||
|
actions.showNotification({
|
||||||
|
icon: 'auction-filled',
|
||||||
|
message: {
|
||||||
|
key: 'GiftAuctionWonNotification',
|
||||||
|
variables: {
|
||||||
|
gift: gift.title,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tabId,
|
||||||
|
});
|
||||||
|
|
||||||
|
actions.requestConfetti({ withStars: true, tabId });
|
||||||
|
});
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
if (!update.message.isOutgoing && update.message.chatId !== SERVICE_NOTIFICATIONS_USER_ID) return undefined;
|
if (!update.message.isOutgoing && update.message.chatId !== SERVICE_NOTIFICATIONS_USER_ID) return undefined;
|
||||||
if (action?.type !== 'starGiftUnique') return undefined;
|
if (action?.type !== 'starGiftUnique') return undefined;
|
||||||
const actionStarGift = action.gift;
|
const actionStarGift = action.gift;
|
||||||
|
|||||||
@ -4,7 +4,12 @@ import { formatCurrencyAsString } from '../../../util/formatCurrency';
|
|||||||
import * as langProvider from '../../../util/oldLangProvider';
|
import * as langProvider from '../../../util/oldLangProvider';
|
||||||
import { getPeerTitle } from '../../helpers/peers';
|
import { getPeerTitle } from '../../helpers/peers';
|
||||||
import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
||||||
import { removeGiftInfoOriginalDetails, updateStarsBalance } from '../../reducers';
|
import {
|
||||||
|
removeGiftInfoOriginalDetails,
|
||||||
|
updateActiveGiftAuctionState,
|
||||||
|
updateActiveGiftAuctionUserState,
|
||||||
|
updateStarsBalance,
|
||||||
|
} from '../../reducers';
|
||||||
import { updateTabState } from '../../reducers/tabs';
|
import { updateTabState } from '../../reducers/tabs';
|
||||||
import { selectPeer, selectTabState } from '../../selectors';
|
import { selectPeer, selectTabState } from '../../selectors';
|
||||||
|
|
||||||
@ -210,6 +215,27 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inputInvoice?.type === 'stargiftAuctionBid') {
|
||||||
|
const { activeGiftAuction } = selectTabState(global, tabId);
|
||||||
|
const giftsPerRound = activeGiftAuction?.gift.giftsPerRound;
|
||||||
|
|
||||||
|
actions.showNotification({
|
||||||
|
icon: 'auction-filled',
|
||||||
|
title: {
|
||||||
|
key: inputInvoice.isUpdateBid ? 'GiftAuctionBidIncreasedTitle' : 'GiftAuctionBidPlacedTitle',
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
key: 'GiftAuctionBidPlacedMessage',
|
||||||
|
variables: { count: giftsPerRound },
|
||||||
|
},
|
||||||
|
tabId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (activeGiftAuction?.gift.id === inputInvoice.giftId) {
|
||||||
|
actions.loadActiveGiftAuction({ giftId: inputInvoice.giftId, tabId });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,5 +247,29 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
|||||||
actions.loadStarStatus();
|
actions.loadStarStatus();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'updateStarGiftAuctionState': {
|
||||||
|
const { giftId, state } = update;
|
||||||
|
|
||||||
|
Object.keys(global.byTabId).forEach((tabIdStr) => {
|
||||||
|
const tabId = Number(tabIdStr);
|
||||||
|
global = updateActiveGiftAuctionState(global, giftId, state, tabId);
|
||||||
|
});
|
||||||
|
|
||||||
|
setGlobal(global);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'updateStarGiftAuctionUserState': {
|
||||||
|
const { giftId, userState } = update;
|
||||||
|
|
||||||
|
Object.keys(global.byTabId).forEach((tabIdStr) => {
|
||||||
|
const tabId = Number(tabIdStr);
|
||||||
|
global = updateActiveGiftAuctionUserState(global, giftId, userState, tabId);
|
||||||
|
});
|
||||||
|
|
||||||
|
setGlobal(global);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -11,8 +11,7 @@ import { callApi } from '../../../api/gramjs';
|
|||||||
import { addTabStateResetterAction } from '../../helpers/meta';
|
import { addTabStateResetterAction } from '../../helpers/meta';
|
||||||
import { getPrizeStarsTransactionFromGiveaway, getStarsTransactionFromGift } from '../../helpers/payments';
|
import { getPrizeStarsTransactionFromGiveaway, getStarsTransactionFromGift } from '../../helpers/payments';
|
||||||
import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
||||||
import {
|
import { clearStarPayment, openStarsTransactionModal,
|
||||||
clearStarPayment, openStarsTransactionModal,
|
|
||||||
} from '../../reducers';
|
} from '../../reducers';
|
||||||
import { updateTabState } from '../../reducers/tabs';
|
import { updateTabState } from '../../reducers/tabs';
|
||||||
import {
|
import {
|
||||||
@ -206,6 +205,31 @@ addTabStateResetterAction('closeStarsSubscriptionModal', 'starsSubscriptionModal
|
|||||||
|
|
||||||
addTabStateResetterAction('closeGiftModal', 'giftModal');
|
addTabStateResetterAction('closeGiftModal', 'giftModal');
|
||||||
|
|
||||||
|
addActionHandler('setGiftModalSelectedGift', (global, actions, payload): ActionReturnType => {
|
||||||
|
const { gift, tabId = getCurrentTabId() } = payload;
|
||||||
|
|
||||||
|
const tabState = selectTabState(global, tabId);
|
||||||
|
const giftModal = tabState?.giftModal;
|
||||||
|
if (giftModal) {
|
||||||
|
return updateTabState(global, {
|
||||||
|
giftModal: {
|
||||||
|
...giftModal,
|
||||||
|
selectedGift: gift,
|
||||||
|
},
|
||||||
|
}, tabId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gift && 'id' in gift) {
|
||||||
|
actions.openGiftModal({
|
||||||
|
forUserId: global.currentUserId!,
|
||||||
|
selectedGift: gift,
|
||||||
|
tabId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
|
||||||
addActionHandler('closeStarsGiftModal', (global, actions, payload): ActionReturnType => {
|
addActionHandler('closeStarsGiftModal', (global, actions, payload): ActionReturnType => {
|
||||||
const { tabId = getCurrentTabId() } = payload || {};
|
const { tabId = getCurrentTabId() } = payload || {};
|
||||||
return updateTabState(global, {
|
return updateTabState(global, {
|
||||||
@ -387,6 +411,52 @@ addTabStateResetterAction('closeGiftResalePriceComposerModal', 'giftResalePriceC
|
|||||||
|
|
||||||
addTabStateResetterAction('closeGiftUpgradeModal', 'giftUpgradeModal');
|
addTabStateResetterAction('closeGiftUpgradeModal', 'giftUpgradeModal');
|
||||||
|
|
||||||
|
addActionHandler('closeGiftAuctionModal', (global, _actions, payload): ActionReturnType => {
|
||||||
|
const { shouldKeepActiveAuction, tabId = getCurrentTabId() } = payload || {};
|
||||||
|
const tabState = selectTabState(global, tabId);
|
||||||
|
|
||||||
|
return updateTabState(global, {
|
||||||
|
giftAuctionModal: undefined,
|
||||||
|
activeGiftAuction: shouldKeepActiveAuction ? tabState?.activeGiftAuction : undefined,
|
||||||
|
}, tabId);
|
||||||
|
});
|
||||||
|
|
||||||
|
addActionHandler('openGiftAuctionBidModal', (global, _actions, payload): ActionReturnType => {
|
||||||
|
const { peerId, message, shouldHideName, tabId = getCurrentTabId() } = payload || {};
|
||||||
|
|
||||||
|
return updateTabState(global, {
|
||||||
|
giftAuctionBidModal: { isOpen: true, peerId, message, shouldHideName },
|
||||||
|
}, tabId);
|
||||||
|
});
|
||||||
|
|
||||||
|
addTabStateResetterAction('closeGiftAuctionBidModal', 'giftAuctionBidModal');
|
||||||
|
|
||||||
|
addActionHandler('openGiftAuctionInfoModal', (global, _actions, payload): ActionReturnType => {
|
||||||
|
const { tabId = getCurrentTabId() } = payload || {};
|
||||||
|
|
||||||
|
return updateTabState(global, {
|
||||||
|
giftAuctionInfoModal: { isOpen: true },
|
||||||
|
}, tabId);
|
||||||
|
});
|
||||||
|
|
||||||
|
addTabStateResetterAction('closeGiftAuctionInfoModal', 'giftAuctionInfoModal');
|
||||||
|
|
||||||
|
addActionHandler('openGiftAuctionChangeRecipientModal', (global, _actions, payload): ActionReturnType => {
|
||||||
|
const {
|
||||||
|
oldPeerId, newPeerId, message, shouldHideName, tabId = getCurrentTabId(),
|
||||||
|
} = payload;
|
||||||
|
|
||||||
|
return updateTabState(global, {
|
||||||
|
giftAuctionChangeRecipientModal: {
|
||||||
|
isOpen: true, oldPeerId, newPeerId, message, shouldHideName,
|
||||||
|
},
|
||||||
|
}, tabId);
|
||||||
|
});
|
||||||
|
|
||||||
|
addTabStateResetterAction('closeGiftAuctionChangeRecipientModal', 'giftAuctionChangeRecipientModal');
|
||||||
|
|
||||||
|
addTabStateResetterAction('closeGiftAuctionAcquiredModal', 'giftAuctionAcquiredModal');
|
||||||
|
|
||||||
addActionHandler('openStarGiftPriceDecreaseInfoModal', (global, actions, payload): ActionReturnType => {
|
addActionHandler('openStarGiftPriceDecreaseInfoModal', (global, actions, payload): ActionReturnType => {
|
||||||
const {
|
const {
|
||||||
prices, currentPrice, minPrice, maxPrice, tabId = getCurrentTabId(),
|
prices, currentPrice, minPrice, maxPrice, tabId = getCurrentTabId(),
|
||||||
|
|||||||
@ -261,6 +261,23 @@ export function getRequestInputInvoice<T extends GlobalState>(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inputInvoice.type === 'stargiftAuctionBid') {
|
||||||
|
const {
|
||||||
|
giftId, bidAmount, peerId, message, shouldHideName, isUpdateBid,
|
||||||
|
} = inputInvoice;
|
||||||
|
const peer = peerId ? selectPeer(global, peerId) : undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'stargiftAuctionBid',
|
||||||
|
giftId,
|
||||||
|
bidAmount,
|
||||||
|
peer,
|
||||||
|
message,
|
||||||
|
shouldHideName,
|
||||||
|
isUpdateBid,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,13 @@
|
|||||||
import type { ApiSavedStarGift } from '../../api/types';
|
import type {
|
||||||
|
ApiSavedStarGift,
|
||||||
|
ApiStarGiftAuctionState,
|
||||||
|
ApiStarGiftAuctionUserState,
|
||||||
|
ApiTypeStarGiftAuctionState,
|
||||||
|
} from '../../api/types';
|
||||||
import type { GlobalState } from '../types';
|
import type { GlobalState } from '../types';
|
||||||
|
|
||||||
import { getCurrentTabId } from '../../util/establishMultitabRole';
|
import { getCurrentTabId } from '../../util/establishMultitabRole';
|
||||||
|
import { selectTabState } from '../selectors';
|
||||||
import { updateTabState } from './tabs';
|
import { updateTabState } from './tabs';
|
||||||
|
|
||||||
export function removeGiftInfoOriginalDetails<T extends GlobalState>(
|
export function removeGiftInfoOriginalDetails<T extends GlobalState>(
|
||||||
@ -46,3 +52,73 @@ export function removeGiftInfoOriginalDetails<T extends GlobalState>(
|
|||||||
},
|
},
|
||||||
}, tabId);
|
}, tabId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getAuctionStateVersion(state: ApiTypeStarGiftAuctionState): number {
|
||||||
|
return state.type === 'active' ? state.version : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateActiveGiftAuction<T extends GlobalState>(
|
||||||
|
global: T,
|
||||||
|
auctionState: ApiStarGiftAuctionState,
|
||||||
|
tabId: number = getCurrentTabId(),
|
||||||
|
): T {
|
||||||
|
const currentAuction = selectTabState(global, tabId).activeGiftAuction;
|
||||||
|
|
||||||
|
const serverVersion = getAuctionStateVersion(auctionState.state);
|
||||||
|
const clientVersion = currentAuction ? getAuctionStateVersion(currentAuction.state) : -1;
|
||||||
|
|
||||||
|
if (serverVersion >= clientVersion) {
|
||||||
|
return updateTabState(global, {
|
||||||
|
activeGiftAuction: auctionState,
|
||||||
|
}, tabId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return global;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateActiveGiftAuctionState<T extends GlobalState>(
|
||||||
|
global: T,
|
||||||
|
giftId: string,
|
||||||
|
state: ApiTypeStarGiftAuctionState,
|
||||||
|
tabId: number,
|
||||||
|
): T {
|
||||||
|
const activeAuction = selectTabState(global, tabId).activeGiftAuction;
|
||||||
|
|
||||||
|
if (!activeAuction || activeAuction.gift.id !== giftId) {
|
||||||
|
return global;
|
||||||
|
}
|
||||||
|
|
||||||
|
const serverVersion = getAuctionStateVersion(state);
|
||||||
|
const clientVersion = getAuctionStateVersion(activeAuction.state);
|
||||||
|
|
||||||
|
if (serverVersion > clientVersion) {
|
||||||
|
return updateTabState(global, {
|
||||||
|
activeGiftAuction: {
|
||||||
|
...activeAuction,
|
||||||
|
state,
|
||||||
|
},
|
||||||
|
}, tabId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return global;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateActiveGiftAuctionUserState<T extends GlobalState>(
|
||||||
|
global: T,
|
||||||
|
giftId: string,
|
||||||
|
userState: ApiStarGiftAuctionUserState,
|
||||||
|
tabId: number,
|
||||||
|
): T {
|
||||||
|
const activeAuction = selectTabState(global, tabId).activeGiftAuction;
|
||||||
|
|
||||||
|
if (!activeAuction || activeAuction.gift.id !== giftId) {
|
||||||
|
return global;
|
||||||
|
}
|
||||||
|
|
||||||
|
return updateTabState(global, {
|
||||||
|
activeGiftAuction: {
|
||||||
|
...activeAuction,
|
||||||
|
userState,
|
||||||
|
},
|
||||||
|
}, tabId);
|
||||||
|
}
|
||||||
|
|||||||
@ -33,6 +33,7 @@ import type {
|
|||||||
ApiPaymentStatus,
|
ApiPaymentStatus,
|
||||||
ApiPeer,
|
ApiPeer,
|
||||||
ApiPhoto,
|
ApiPhoto,
|
||||||
|
ApiPremiumGiftCodeOption,
|
||||||
ApiPremiumSection,
|
ApiPremiumSection,
|
||||||
ApiPreparedInlineMessage,
|
ApiPreparedInlineMessage,
|
||||||
ApiPrivacyKey,
|
ApiPrivacyKey,
|
||||||
@ -46,6 +47,7 @@ import type {
|
|||||||
ApiSessionData,
|
ApiSessionData,
|
||||||
ApiStarGift,
|
ApiStarGift,
|
||||||
ApiStarGiftAttributeOriginalDetails,
|
ApiStarGiftAttributeOriginalDetails,
|
||||||
|
ApiStarGiftRegular,
|
||||||
ApiStarGiftUnique,
|
ApiStarGiftUnique,
|
||||||
ApiStarGiftUpgradePrice,
|
ApiStarGiftUpgradePrice,
|
||||||
ApiStarsSubscription,
|
ApiStarsSubscription,
|
||||||
@ -1653,6 +1655,9 @@ export interface ActionPayloads {
|
|||||||
openUniqueGiftBySlug: {
|
openUniqueGiftBySlug: {
|
||||||
slug: string;
|
slug: string;
|
||||||
} & WithTabId;
|
} & WithTabId;
|
||||||
|
openGiftAuctionBySlug: {
|
||||||
|
slug: string;
|
||||||
|
} & WithTabId;
|
||||||
openPreviousStory: WithTabId | undefined;
|
openPreviousStory: WithTabId | undefined;
|
||||||
openNextStory: WithTabId | undefined;
|
openNextStory: WithTabId | undefined;
|
||||||
setStoryViewerMuted: {
|
setStoryViewerMuted: {
|
||||||
@ -2600,9 +2605,13 @@ export interface ActionPayloads {
|
|||||||
|
|
||||||
openGiftModal: {
|
openGiftModal: {
|
||||||
forUserId: string;
|
forUserId: string;
|
||||||
|
selectedGift?: ApiStarGift;
|
||||||
selectedResaleGift?: ApiStarGift;
|
selectedResaleGift?: ApiStarGift;
|
||||||
} & WithTabId;
|
} & WithTabId;
|
||||||
closeGiftModal: WithTabId | undefined;
|
closeGiftModal: WithTabId | undefined;
|
||||||
|
setGiftModalSelectedGift: {
|
||||||
|
gift: ApiPremiumGiftCodeOption | ApiStarGift | undefined;
|
||||||
|
} & WithTabId;
|
||||||
sendStarGift: StarGiftInfo & WithTabId;
|
sendStarGift: StarGiftInfo & WithTabId;
|
||||||
buyStarGift: {
|
buyStarGift: {
|
||||||
peerId: string;
|
peerId: string;
|
||||||
@ -2686,6 +2695,45 @@ export interface ActionPayloads {
|
|||||||
gift: ApiStarGiftUnique;
|
gift: ApiStarGiftUnique;
|
||||||
} & WithTabId;
|
} & WithTabId;
|
||||||
closeGiftInfoValueModal: WithTabId | undefined;
|
closeGiftInfoValueModal: WithTabId | undefined;
|
||||||
|
openGiftAuctionModal: {
|
||||||
|
gift: ApiStarGiftRegular;
|
||||||
|
} & WithTabId;
|
||||||
|
closeGiftAuctionModal: {
|
||||||
|
shouldKeepActiveAuction?: boolean;
|
||||||
|
} & WithTabId | undefined;
|
||||||
|
openGiftAuctionBidModal: {
|
||||||
|
peerId?: string;
|
||||||
|
message?: string;
|
||||||
|
shouldHideName?: boolean;
|
||||||
|
} & WithTabId | undefined;
|
||||||
|
closeGiftAuctionBidModal: WithTabId | undefined;
|
||||||
|
openGiftAuctionInfoModal: WithTabId | undefined;
|
||||||
|
closeGiftAuctionInfoModal: WithTabId | undefined;
|
||||||
|
openGiftAuctionChangeRecipientModal: {
|
||||||
|
oldPeerId: string;
|
||||||
|
newPeerId: string;
|
||||||
|
message?: string;
|
||||||
|
shouldHideName?: boolean;
|
||||||
|
} & WithTabId;
|
||||||
|
closeGiftAuctionChangeRecipientModal: WithTabId | undefined;
|
||||||
|
openGiftAuctionAcquiredModal: {
|
||||||
|
giftId: string;
|
||||||
|
giftTitle?: string;
|
||||||
|
giftSticker?: ApiSticker;
|
||||||
|
} & WithTabId;
|
||||||
|
closeGiftAuctionAcquiredModal: WithTabId | undefined;
|
||||||
|
sendStarGiftAuctionBid: {
|
||||||
|
giftId: string;
|
||||||
|
bidAmount: number;
|
||||||
|
peerId?: string;
|
||||||
|
message?: ApiFormattedText;
|
||||||
|
shouldHideName?: boolean;
|
||||||
|
isUpdateBid?: boolean;
|
||||||
|
} & WithTabId;
|
||||||
|
loadActiveGiftAuction: {
|
||||||
|
giftId: string;
|
||||||
|
} & WithTabId;
|
||||||
|
clearActiveGiftAuction: WithTabId | undefined;
|
||||||
processStarGiftWithdrawal: {
|
processStarGiftWithdrawal: {
|
||||||
gift: ApiInputSavedStarGift;
|
gift: ApiInputSavedStarGift;
|
||||||
password: string;
|
password: string;
|
||||||
|
|||||||
@ -44,6 +44,8 @@ import type {
|
|||||||
ApiStarGiftAttribute,
|
ApiStarGiftAttribute,
|
||||||
ApiStarGiftAttributeCounter,
|
ApiStarGiftAttributeCounter,
|
||||||
ApiStarGiftAttributeOriginalDetails,
|
ApiStarGiftAttributeOriginalDetails,
|
||||||
|
ApiStarGiftAuctionAcquiredGift,
|
||||||
|
ApiStarGiftAuctionState,
|
||||||
ApiStarGiftUnique,
|
ApiStarGiftUnique,
|
||||||
ApiStarGiftUpgradePrice,
|
ApiStarGiftUpgradePrice,
|
||||||
ApiStarGiveawayOption,
|
ApiStarGiveawayOption,
|
||||||
@ -703,7 +705,9 @@ export type TabState = {
|
|||||||
forPeerId: string;
|
forPeerId: string;
|
||||||
gifts?: ApiPremiumGiftCodeOption[];
|
gifts?: ApiPremiumGiftCodeOption[];
|
||||||
selectedResaleGift?: ApiStarGift;
|
selectedResaleGift?: ApiStarGift;
|
||||||
|
selectedGift?: ApiPremiumGiftCodeOption | ApiStarGift;
|
||||||
};
|
};
|
||||||
|
activeGiftAuction?: ApiStarGiftAuctionState;
|
||||||
chatRefundModal?: {
|
chatRefundModal?: {
|
||||||
userId: string;
|
userId: string;
|
||||||
starsToRefund: number;
|
starsToRefund: number;
|
||||||
@ -889,6 +893,36 @@ export type TabState = {
|
|||||||
emojiStatus: ApiEmojiStatusCollectible;
|
emojiStatus: ApiEmojiStatusCollectible;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
giftAuctionModal?: {
|
||||||
|
isOpen?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
giftAuctionBidModal?: {
|
||||||
|
isOpen?: boolean;
|
||||||
|
peerId?: string;
|
||||||
|
message?: string;
|
||||||
|
shouldHideName?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
giftAuctionInfoModal?: {
|
||||||
|
isOpen?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
giftAuctionChangeRecipientModal?: {
|
||||||
|
isOpen?: boolean;
|
||||||
|
oldPeerId?: string;
|
||||||
|
newPeerId?: string;
|
||||||
|
message?: string;
|
||||||
|
shouldHideName?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
giftAuctionAcquiredModal?: {
|
||||||
|
giftId?: string;
|
||||||
|
giftTitle?: string;
|
||||||
|
giftSticker?: ApiSticker;
|
||||||
|
acquiredGifts?: ApiStarGiftAuctionAcquiredGift[];
|
||||||
|
};
|
||||||
|
|
||||||
starGiftPriceDecreaseInfoModal?: {
|
starGiftPriceDecreaseInfoModal?: {
|
||||||
prices: ApiStarGiftUpgradePrice[];
|
prices: ApiStarGiftUpgradePrice[];
|
||||||
currentPrice: number;
|
currentPrice: number;
|
||||||
|
|||||||
@ -12,10 +12,12 @@ const useScrollNotch = ({
|
|||||||
containerRef,
|
containerRef,
|
||||||
selector,
|
selector,
|
||||||
isBottomNotch,
|
isBottomNotch,
|
||||||
|
shouldHideTopNotch,
|
||||||
}: {
|
}: {
|
||||||
containerRef: ElementRef<HTMLDivElement>;
|
containerRef: ElementRef<HTMLDivElement>;
|
||||||
selector: string;
|
selector: string;
|
||||||
isBottomNotch?: boolean;
|
isBottomNotch?: boolean;
|
||||||
|
shouldHideTopNotch?: boolean;
|
||||||
}, deps: unknown[]) => {
|
}, deps: unknown[]) => {
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const elements = containerRef.current?.querySelectorAll<HTMLElement>(selector);
|
const elements = containerRef.current?.querySelectorAll<HTMLElement>(selector);
|
||||||
@ -28,19 +30,21 @@ const useScrollNotch = ({
|
|||||||
const isAtEnd = scrollHeight - scrollTop - clientHeight < SCROLL_THRESHOLD;
|
const isAtEnd = scrollHeight - scrollTop - clientHeight < SCROLL_THRESHOLD;
|
||||||
|
|
||||||
requestMutation(() => {
|
requestMutation(() => {
|
||||||
|
if (!shouldHideTopNotch) {
|
||||||
|
toggleExtraClass(target, 'scrolled', isScrolled);
|
||||||
|
}
|
||||||
if (isBottomNotch) {
|
if (isBottomNotch) {
|
||||||
toggleExtraClass(target, 'scrolled-to-end', isAtEnd);
|
toggleExtraClass(target, 'scrolled-to-end', isAtEnd);
|
||||||
} else {
|
|
||||||
toggleExtraClass(target, 'scrolled', isScrolled);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, THROTTLE_DELAY);
|
}, THROTTLE_DELAY);
|
||||||
|
|
||||||
elements.forEach((el) => {
|
elements.forEach((el) => {
|
||||||
|
if (!shouldHideTopNotch) {
|
||||||
|
addExtraClass(el, 'with-notch');
|
||||||
|
}
|
||||||
if (isBottomNotch) {
|
if (isBottomNotch) {
|
||||||
addExtraClass(el, 'with-bottom-notch');
|
addExtraClass(el, 'with-bottom-notch');
|
||||||
} else {
|
|
||||||
addExtraClass(el, 'with-notch');
|
|
||||||
}
|
}
|
||||||
el.addEventListener('scroll', handleScroll, { passive: true });
|
el.addEventListener('scroll', handleScroll, { passive: true });
|
||||||
});
|
});
|
||||||
@ -55,7 +59,7 @@ const useScrollNotch = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
// eslint-disable-next-line react-hooks-static-deps/exhaustive-deps
|
// eslint-disable-next-line react-hooks-static-deps/exhaustive-deps
|
||||||
}, [containerRef, selector, isBottomNotch, ...deps]);
|
}, [containerRef, selector, isBottomNotch, shouldHideTopNotch, ...deps]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const elements = containerRef.current?.querySelectorAll<HTMLElement>(selector);
|
const elements = containerRef.current?.querySelectorAll<HTMLElement>(selector);
|
||||||
@ -67,15 +71,16 @@ const useScrollNotch = ({
|
|||||||
const isAtEnd = scrollHeight - scrollTop - clientHeight < SCROLL_THRESHOLD;
|
const isAtEnd = scrollHeight - scrollTop - clientHeight < SCROLL_THRESHOLD;
|
||||||
|
|
||||||
requestMutation(() => {
|
requestMutation(() => {
|
||||||
|
if (!shouldHideTopNotch) {
|
||||||
|
toggleExtraClass(el, 'scrolled', isScrolled);
|
||||||
|
}
|
||||||
if (isBottomNotch) {
|
if (isBottomNotch) {
|
||||||
toggleExtraClass(el, 'scrolled-to-end', isAtEnd);
|
toggleExtraClass(el, 'scrolled-to-end', isAtEnd);
|
||||||
} else {
|
|
||||||
toggleExtraClass(el, 'scrolled', isScrolled);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// eslint-disable-next-line react-hooks-static-deps/exhaustive-deps
|
// eslint-disable-next-line react-hooks-static-deps/exhaustive-deps
|
||||||
}, [containerRef, selector, isBottomNotch, ...deps]);
|
}, [containerRef, selector, isBottomNotch, shouldHideTopNotch, ...deps]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useScrollNotch;
|
export default useScrollNotch;
|
||||||
|
|||||||
@ -1881,6 +1881,8 @@ payments.updateStarGiftPrice#edbe6ccb stargift:InputSavedStarGift resell_amount:
|
|||||||
payments.getStarGiftCollections#981b91dd peer:InputPeer hash:long = payments.StarGiftCollections;
|
payments.getStarGiftCollections#981b91dd peer:InputPeer hash:long = payments.StarGiftCollections;
|
||||||
payments.getUniqueStarGiftValueInfo#4365af6b slug:string = payments.UniqueStarGiftValueInfo;
|
payments.getUniqueStarGiftValueInfo#4365af6b slug:string = payments.UniqueStarGiftValueInfo;
|
||||||
payments.checkCanSendGift#c0c4edc9 gift_id:long = payments.CheckCanSendGiftResult;
|
payments.checkCanSendGift#c0c4edc9 gift_id:long = payments.CheckCanSendGiftResult;
|
||||||
|
payments.getStarGiftAuctionState#5c9ff4d6 auction:InputStarGiftAuction version:int = payments.StarGiftAuctionState;
|
||||||
|
payments.getStarGiftAuctionAcquiredGifts#6ba2cbec gift_id:long = payments.StarGiftAuctionAcquiredGifts;
|
||||||
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;
|
||||||
|
|||||||
@ -352,6 +352,8 @@
|
|||||||
"payments.getResaleStarGifts",
|
"payments.getResaleStarGifts",
|
||||||
"payments.updateStarGiftPrice",
|
"payments.updateStarGiftPrice",
|
||||||
"payments.getStarGiftCollections",
|
"payments.getStarGiftCollections",
|
||||||
|
"payments.getStarGiftAuctionState",
|
||||||
|
"payments.getStarGiftAuctionAcquiredGifts",
|
||||||
"langpack.getLangPack",
|
"langpack.getLangPack",
|
||||||
"langpack.getStrings",
|
"langpack.getStrings",
|
||||||
"langpack.getLanguages",
|
"langpack.getLanguages",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -35,292 +35,295 @@ $icons-map: (
|
|||||||
"arrow-right": "\f111",
|
"arrow-right": "\f111",
|
||||||
"ask-support": "\f112",
|
"ask-support": "\f112",
|
||||||
"attach": "\f113",
|
"attach": "\f113",
|
||||||
"auction": "\f114",
|
"auction-drop": "\f114",
|
||||||
"author-hidden": "\f115",
|
"auction-filled": "\f115",
|
||||||
"avatar-archived-chats": "\f116",
|
"auction-next-round": "\f116",
|
||||||
"avatar-deleted-account": "\f117",
|
"auction": "\f117",
|
||||||
"avatar-saved-messages": "\f118",
|
"author-hidden": "\f118",
|
||||||
"bold": "\f119",
|
"avatar-archived-chats": "\f119",
|
||||||
"boost-outline": "\f11a",
|
"avatar-deleted-account": "\f11a",
|
||||||
"boost": "\f11b",
|
"avatar-saved-messages": "\f11b",
|
||||||
"boostcircle": "\f11c",
|
"bold": "\f11c",
|
||||||
"boosts": "\f11d",
|
"boost-outline": "\f11d",
|
||||||
"bot-command": "\f11e",
|
"boost": "\f11e",
|
||||||
"bot-commands-filled": "\f11f",
|
"boostcircle": "\f11f",
|
||||||
"bots": "\f120",
|
"boosts": "\f120",
|
||||||
"bug": "\f121",
|
"bot-command": "\f121",
|
||||||
"calendar-filter": "\f122",
|
"bot-commands-filled": "\f122",
|
||||||
"calendar": "\f123",
|
"bots": "\f123",
|
||||||
"camera-add": "\f124",
|
"bug": "\f124",
|
||||||
"camera": "\f125",
|
"calendar-filter": "\f125",
|
||||||
"car": "\f126",
|
"calendar": "\f126",
|
||||||
"card": "\f127",
|
"camera-add": "\f127",
|
||||||
"cash-circle": "\f128",
|
"camera": "\f128",
|
||||||
"channel-filled": "\f129",
|
"car": "\f129",
|
||||||
"channel": "\f12a",
|
"card": "\f12a",
|
||||||
"channelviews": "\f12b",
|
"cash-circle": "\f12b",
|
||||||
"chat-badge": "\f12c",
|
"channel-filled": "\f12c",
|
||||||
"chats-badge": "\f12d",
|
"channel": "\f12d",
|
||||||
"check": "\f12e",
|
"channelviews": "\f12e",
|
||||||
"clock-edit": "\f12f",
|
"chat-badge": "\f12f",
|
||||||
"clock": "\f130",
|
"chats-badge": "\f130",
|
||||||
"close-circle": "\f131",
|
"check": "\f131",
|
||||||
"close-topic": "\f132",
|
"clock-edit": "\f132",
|
||||||
"close": "\f133",
|
"clock": "\f133",
|
||||||
"closed-gift": "\f134",
|
"close-circle": "\f134",
|
||||||
"cloud-download": "\f135",
|
"close-topic": "\f135",
|
||||||
"collapse-modal": "\f136",
|
"close": "\f136",
|
||||||
"collapse": "\f137",
|
"closed-gift": "\f137",
|
||||||
"colorize": "\f138",
|
"cloud-download": "\f138",
|
||||||
"comments-sticker": "\f139",
|
"collapse-modal": "\f139",
|
||||||
"comments": "\f13a",
|
"collapse": "\f13a",
|
||||||
"copy-media": "\f13b",
|
"colorize": "\f13b",
|
||||||
"copy": "\f13c",
|
"comments-sticker": "\f13c",
|
||||||
"crown-take-off-outline": "\f13d",
|
"comments": "\f13d",
|
||||||
"crown-take-off": "\f13e",
|
"copy-media": "\f13e",
|
||||||
"crown-wear-outline": "\f13f",
|
"copy": "\f13f",
|
||||||
"crown-wear": "\f140",
|
"crown-take-off-outline": "\f140",
|
||||||
"darkmode": "\f141",
|
"crown-take-off": "\f141",
|
||||||
"data": "\f142",
|
"crown-wear-outline": "\f142",
|
||||||
"delete-filled": "\f143",
|
"crown-wear": "\f143",
|
||||||
"delete-left": "\f144",
|
"darkmode": "\f144",
|
||||||
"delete-user": "\f145",
|
"data": "\f145",
|
||||||
"delete": "\f146",
|
"delete-filled": "\f146",
|
||||||
"diamond": "\f147",
|
"delete-left": "\f147",
|
||||||
"document": "\f148",
|
"delete-user": "\f148",
|
||||||
"double-badge": "\f149",
|
"delete": "\f149",
|
||||||
"down": "\f14a",
|
"diamond": "\f14a",
|
||||||
"download": "\f14b",
|
"document": "\f14b",
|
||||||
"dropdown-arrows": "\f14c",
|
"double-badge": "\f14c",
|
||||||
"eats": "\f14d",
|
"down": "\f14d",
|
||||||
"edit": "\f14e",
|
"download": "\f14e",
|
||||||
"email": "\f14f",
|
"dropdown-arrows": "\f14f",
|
||||||
"enter": "\f150",
|
"eats": "\f150",
|
||||||
"expand-modal": "\f151",
|
"edit": "\f151",
|
||||||
"expand": "\f152",
|
"email": "\f152",
|
||||||
"eye-crossed-outline": "\f153",
|
"enter": "\f153",
|
||||||
"eye-crossed": "\f154",
|
"expand-modal": "\f154",
|
||||||
"eye-outline": "\f155",
|
"expand": "\f155",
|
||||||
"eye": "\f156",
|
"eye-crossed-outline": "\f156",
|
||||||
"favorite-filled": "\f157",
|
"eye-crossed": "\f157",
|
||||||
"favorite": "\f158",
|
"eye-outline": "\f158",
|
||||||
"file-badge": "\f159",
|
"eye": "\f159",
|
||||||
"flag": "\f15a",
|
"favorite-filled": "\f15a",
|
||||||
"folder-badge": "\f15b",
|
"favorite": "\f15b",
|
||||||
"folder-tabs-bot": "\f15c",
|
"file-badge": "\f15c",
|
||||||
"folder-tabs-channel": "\f15d",
|
"flag": "\f15d",
|
||||||
"folder-tabs-chat": "\f15e",
|
"folder-badge": "\f15e",
|
||||||
"folder-tabs-chats": "\f15f",
|
"folder-tabs-bot": "\f15f",
|
||||||
"folder-tabs-folder": "\f160",
|
"folder-tabs-channel": "\f160",
|
||||||
"folder-tabs-group": "\f161",
|
"folder-tabs-chat": "\f161",
|
||||||
"folder-tabs-star": "\f162",
|
"folder-tabs-chats": "\f162",
|
||||||
"folder-tabs-user": "\f163",
|
"folder-tabs-folder": "\f163",
|
||||||
"folder": "\f164",
|
"folder-tabs-group": "\f164",
|
||||||
"fontsize": "\f165",
|
"folder-tabs-star": "\f165",
|
||||||
"forums": "\f166",
|
"folder-tabs-user": "\f166",
|
||||||
"forward": "\f167",
|
"folder": "\f167",
|
||||||
"fragment": "\f168",
|
"fontsize": "\f168",
|
||||||
"frozen-time": "\f169",
|
"forums": "\f169",
|
||||||
"fullscreen": "\f16a",
|
"forward": "\f16a",
|
||||||
"gifs": "\f16b",
|
"fragment": "\f16b",
|
||||||
"gift-transfer-inline": "\f16c",
|
"frozen-time": "\f16c",
|
||||||
"gift": "\f16d",
|
"fullscreen": "\f16d",
|
||||||
"group-filled": "\f16e",
|
"gifs": "\f16e",
|
||||||
"group": "\f16f",
|
"gift-transfer-inline": "\f16f",
|
||||||
"grouped-disable": "\f170",
|
"gift": "\f170",
|
||||||
"grouped": "\f171",
|
"group-filled": "\f171",
|
||||||
"hand-stop": "\f172",
|
"group": "\f172",
|
||||||
"hashtag": "\f173",
|
"grouped-disable": "\f173",
|
||||||
"hd-photo": "\f174",
|
"grouped": "\f174",
|
||||||
"heart-outline": "\f175",
|
"hand-stop": "\f175",
|
||||||
"heart": "\f176",
|
"hashtag": "\f176",
|
||||||
"help": "\f177",
|
"hd-photo": "\f177",
|
||||||
"info-filled": "\f178",
|
"heart-outline": "\f178",
|
||||||
"info": "\f179",
|
"heart": "\f179",
|
||||||
"install": "\f17a",
|
"help": "\f17a",
|
||||||
"italic": "\f17b",
|
"info-filled": "\f17b",
|
||||||
"key": "\f17c",
|
"info": "\f17c",
|
||||||
"keyboard": "\f17d",
|
"install": "\f17d",
|
||||||
"lamp": "\f17e",
|
"italic": "\f17e",
|
||||||
"language": "\f17f",
|
"key": "\f17f",
|
||||||
"large-pause": "\f180",
|
"keyboard": "\f180",
|
||||||
"large-play": "\f181",
|
"lamp": "\f181",
|
||||||
"link-badge": "\f182",
|
"language": "\f182",
|
||||||
"link-broken": "\f183",
|
"large-pause": "\f183",
|
||||||
"link": "\f184",
|
"large-play": "\f184",
|
||||||
"location": "\f185",
|
"link-badge": "\f185",
|
||||||
"lock-badge": "\f186",
|
"link-broken": "\f186",
|
||||||
"lock": "\f187",
|
"link": "\f187",
|
||||||
"logout": "\f188",
|
"location": "\f188",
|
||||||
"loop": "\f189",
|
"lock-badge": "\f189",
|
||||||
"mention": "\f18a",
|
"lock": "\f18a",
|
||||||
"menu": "\f18b",
|
"logout": "\f18b",
|
||||||
"message-failed": "\f18c",
|
"loop": "\f18c",
|
||||||
"message-pending": "\f18d",
|
"mention": "\f18d",
|
||||||
"message-read": "\f18e",
|
"menu": "\f18e",
|
||||||
"message-succeeded": "\f18f",
|
"message-failed": "\f18f",
|
||||||
"message": "\f190",
|
"message-pending": "\f190",
|
||||||
"microphone-alt": "\f191",
|
"message-read": "\f191",
|
||||||
"microphone": "\f192",
|
"message-succeeded": "\f192",
|
||||||
"monospace": "\f193",
|
"message": "\f193",
|
||||||
"more-circle": "\f194",
|
"microphone-alt": "\f194",
|
||||||
"more": "\f195",
|
"microphone": "\f195",
|
||||||
"move-caption-down": "\f196",
|
"monospace": "\f196",
|
||||||
"move-caption-up": "\f197",
|
"more-circle": "\f197",
|
||||||
"mute": "\f198",
|
"more": "\f198",
|
||||||
"muted": "\f199",
|
"move-caption-down": "\f199",
|
||||||
"my-notes": "\f19a",
|
"move-caption-up": "\f19a",
|
||||||
"new-chat-filled": "\f19b",
|
"mute": "\f19b",
|
||||||
"next": "\f19c",
|
"muted": "\f19c",
|
||||||
"nochannel": "\f19d",
|
"my-notes": "\f19d",
|
||||||
"noise-suppression": "\f19e",
|
"new-chat-filled": "\f19e",
|
||||||
"non-contacts": "\f19f",
|
"next": "\f19f",
|
||||||
"note": "\f1a0",
|
"nochannel": "\f1a0",
|
||||||
"one-filled": "\f1a1",
|
"noise-suppression": "\f1a1",
|
||||||
"open-in-new-tab": "\f1a2",
|
"non-contacts": "\f1a2",
|
||||||
"password-off": "\f1a3",
|
"note": "\f1a3",
|
||||||
"pause": "\f1a4",
|
"one-filled": "\f1a4",
|
||||||
"permissions": "\f1a5",
|
"open-in-new-tab": "\f1a5",
|
||||||
"phone-discard-outline": "\f1a6",
|
"password-off": "\f1a6",
|
||||||
"phone-discard": "\f1a7",
|
"pause": "\f1a7",
|
||||||
"phone": "\f1a8",
|
"permissions": "\f1a8",
|
||||||
"photo": "\f1a9",
|
"phone-discard-outline": "\f1a9",
|
||||||
"pin-badge": "\f1aa",
|
"phone-discard": "\f1aa",
|
||||||
"pin-list": "\f1ab",
|
"phone": "\f1ab",
|
||||||
"pin": "\f1ac",
|
"photo": "\f1ac",
|
||||||
"pinned-chat": "\f1ad",
|
"pin-badge": "\f1ad",
|
||||||
"pinned-message": "\f1ae",
|
"pin-list": "\f1ae",
|
||||||
"pip": "\f1af",
|
"pin": "\f1af",
|
||||||
"play-story": "\f1b0",
|
"pinned-chat": "\f1b0",
|
||||||
"play": "\f1b1",
|
"pinned-message": "\f1b1",
|
||||||
"poll": "\f1b2",
|
"pip": "\f1b2",
|
||||||
"previous": "\f1b3",
|
"play-story": "\f1b3",
|
||||||
"privacy-policy": "\f1b4",
|
"play": "\f1b4",
|
||||||
"proof-of-ownership": "\f1b5",
|
"poll": "\f1b5",
|
||||||
"quote-text": "\f1b6",
|
"previous": "\f1b6",
|
||||||
"quote": "\f1b7",
|
"privacy-policy": "\f1b7",
|
||||||
"radial-badge": "\f1b8",
|
"proof-of-ownership": "\f1b8",
|
||||||
"rating-icons-level1": "\f1b9",
|
"quote-text": "\f1b9",
|
||||||
"rating-icons-level10": "\f1ba",
|
"quote": "\f1ba",
|
||||||
"rating-icons-level2": "\f1bb",
|
"radial-badge": "\f1bb",
|
||||||
"rating-icons-level20": "\f1bc",
|
"rating-icons-level1": "\f1bc",
|
||||||
"rating-icons-level3": "\f1bd",
|
"rating-icons-level10": "\f1bd",
|
||||||
"rating-icons-level30": "\f1be",
|
"rating-icons-level2": "\f1be",
|
||||||
"rating-icons-level4": "\f1bf",
|
"rating-icons-level20": "\f1bf",
|
||||||
"rating-icons-level40": "\f1c0",
|
"rating-icons-level3": "\f1c0",
|
||||||
"rating-icons-level5": "\f1c1",
|
"rating-icons-level30": "\f1c1",
|
||||||
"rating-icons-level50": "\f1c2",
|
"rating-icons-level4": "\f1c2",
|
||||||
"rating-icons-level6": "\f1c3",
|
"rating-icons-level40": "\f1c3",
|
||||||
"rating-icons-level60": "\f1c4",
|
"rating-icons-level5": "\f1c4",
|
||||||
"rating-icons-level7": "\f1c5",
|
"rating-icons-level50": "\f1c5",
|
||||||
"rating-icons-level70": "\f1c6",
|
"rating-icons-level6": "\f1c6",
|
||||||
"rating-icons-level8": "\f1c7",
|
"rating-icons-level60": "\f1c7",
|
||||||
"rating-icons-level80": "\f1c8",
|
"rating-icons-level7": "\f1c8",
|
||||||
"rating-icons-level9": "\f1c9",
|
"rating-icons-level70": "\f1c9",
|
||||||
"rating-icons-level90": "\f1ca",
|
"rating-icons-level8": "\f1ca",
|
||||||
"rating-icons-negative": "\f1cb",
|
"rating-icons-level80": "\f1cb",
|
||||||
"readchats": "\f1cc",
|
"rating-icons-level9": "\f1cc",
|
||||||
"recent": "\f1cd",
|
"rating-icons-level90": "\f1cd",
|
||||||
"refund": "\f1ce",
|
"rating-icons-negative": "\f1ce",
|
||||||
"reload": "\f1cf",
|
"readchats": "\f1cf",
|
||||||
"remove-quote": "\f1d0",
|
"recent": "\f1d0",
|
||||||
"remove": "\f1d1",
|
"refund": "\f1d1",
|
||||||
"reopen-topic": "\f1d2",
|
"reload": "\f1d2",
|
||||||
"reorder-tabs": "\f1d3",
|
"remove-quote": "\f1d3",
|
||||||
"replace": "\f1d4",
|
"remove": "\f1d4",
|
||||||
"replies": "\f1d5",
|
"reopen-topic": "\f1d5",
|
||||||
"reply-filled": "\f1d6",
|
"reorder-tabs": "\f1d6",
|
||||||
"reply": "\f1d7",
|
"replace": "\f1d7",
|
||||||
"revenue-split": "\f1d8",
|
"replies": "\f1d8",
|
||||||
"revote": "\f1d9",
|
"reply-filled": "\f1d9",
|
||||||
"save-story": "\f1da",
|
"reply": "\f1da",
|
||||||
"saved-messages": "\f1db",
|
"revenue-split": "\f1db",
|
||||||
"schedule": "\f1dc",
|
"revote": "\f1dc",
|
||||||
"scheduled": "\f1dd",
|
"save-story": "\f1dd",
|
||||||
"sd-photo": "\f1de",
|
"saved-messages": "\f1de",
|
||||||
"search": "\f1df",
|
"schedule": "\f1df",
|
||||||
"select": "\f1e0",
|
"scheduled": "\f1e0",
|
||||||
"sell-outline": "\f1e1",
|
"sd-photo": "\f1e1",
|
||||||
"sell": "\f1e2",
|
"search": "\f1e2",
|
||||||
"send-outline": "\f1e3",
|
"select": "\f1e3",
|
||||||
"send": "\f1e4",
|
"sell-outline": "\f1e4",
|
||||||
"settings-filled": "\f1e5",
|
"sell": "\f1e5",
|
||||||
"settings": "\f1e6",
|
"send-outline": "\f1e6",
|
||||||
"share-filled": "\f1e7",
|
"send": "\f1e7",
|
||||||
"share-screen-outlined": "\f1e8",
|
"settings-filled": "\f1e8",
|
||||||
"share-screen-stop": "\f1e9",
|
"settings": "\f1e9",
|
||||||
"share-screen": "\f1ea",
|
"share-filled": "\f1ea",
|
||||||
"show-message": "\f1eb",
|
"share-screen-outlined": "\f1eb",
|
||||||
"sidebar": "\f1ec",
|
"share-screen-stop": "\f1ec",
|
||||||
"skip-next": "\f1ed",
|
"share-screen": "\f1ed",
|
||||||
"skip-previous": "\f1ee",
|
"show-message": "\f1ee",
|
||||||
"smallscreen": "\f1ef",
|
"sidebar": "\f1ef",
|
||||||
"smile": "\f1f0",
|
"skip-next": "\f1f0",
|
||||||
"sort-by-date": "\f1f1",
|
"skip-previous": "\f1f1",
|
||||||
"sort-by-number": "\f1f2",
|
"smallscreen": "\f1f2",
|
||||||
"sort-by-price": "\f1f3",
|
"smile": "\f1f3",
|
||||||
"sort": "\f1f4",
|
"sort-by-date": "\f1f4",
|
||||||
"speaker-muted-story": "\f1f5",
|
"sort-by-number": "\f1f5",
|
||||||
"speaker-outline": "\f1f6",
|
"sort-by-price": "\f1f6",
|
||||||
"speaker-story": "\f1f7",
|
"sort": "\f1f7",
|
||||||
"speaker": "\f1f8",
|
"speaker-muted-story": "\f1f8",
|
||||||
"spoiler-disable": "\f1f9",
|
"speaker-outline": "\f1f9",
|
||||||
"spoiler": "\f1fa",
|
"speaker-story": "\f1fa",
|
||||||
"sport": "\f1fb",
|
"speaker": "\f1fb",
|
||||||
"star": "\f1fc",
|
"spoiler-disable": "\f1fc",
|
||||||
"stars-lock": "\f1fd",
|
"spoiler": "\f1fd",
|
||||||
"stars-refund": "\f1fe",
|
"sport": "\f1fe",
|
||||||
"stats": "\f1ff",
|
"star": "\f1ff",
|
||||||
"stealth-future": "\f200",
|
"stars-lock": "\f200",
|
||||||
"stealth-past": "\f201",
|
"stars-refund": "\f201",
|
||||||
"stickers": "\f202",
|
"stats": "\f202",
|
||||||
"stop-raising-hand": "\f203",
|
"stealth-future": "\f203",
|
||||||
"stop": "\f204",
|
"stealth-past": "\f204",
|
||||||
"story-caption": "\f205",
|
"stickers": "\f205",
|
||||||
"story-expired": "\f206",
|
"stop-raising-hand": "\f206",
|
||||||
"story-priority": "\f207",
|
"stop": "\f207",
|
||||||
"story-reply": "\f208",
|
"story-caption": "\f208",
|
||||||
"strikethrough": "\f209",
|
"story-expired": "\f209",
|
||||||
"tag-add": "\f20a",
|
"story-priority": "\f20a",
|
||||||
"tag-crossed": "\f20b",
|
"story-reply": "\f20b",
|
||||||
"tag-filter": "\f20c",
|
"strikethrough": "\f20c",
|
||||||
"tag-name": "\f20d",
|
"tag-add": "\f20d",
|
||||||
"tag": "\f20e",
|
"tag-crossed": "\f20e",
|
||||||
"timer": "\f20f",
|
"tag-filter": "\f20f",
|
||||||
"toncoin": "\f210",
|
"tag-name": "\f210",
|
||||||
"tools": "\f211",
|
"tag": "\f211",
|
||||||
"topic-new": "\f212",
|
"timer": "\f212",
|
||||||
"trade": "\f213",
|
"toncoin": "\f213",
|
||||||
"transcribe": "\f214",
|
"tools": "\f214",
|
||||||
"truck": "\f215",
|
"topic-new": "\f215",
|
||||||
"unarchive": "\f216",
|
"trade": "\f216",
|
||||||
"underlined": "\f217",
|
"transcribe": "\f217",
|
||||||
"understood": "\f218",
|
"truck": "\f218",
|
||||||
"unique-profile": "\f219",
|
"unarchive": "\f219",
|
||||||
"unlist-outline": "\f21a",
|
"underlined": "\f21a",
|
||||||
"unlist": "\f21b",
|
"understood": "\f21b",
|
||||||
"unlock-badge": "\f21c",
|
"unique-profile": "\f21c",
|
||||||
"unlock": "\f21d",
|
"unlist-outline": "\f21d",
|
||||||
"unmute": "\f21e",
|
"unlist": "\f21e",
|
||||||
"unpin": "\f21f",
|
"unlock-badge": "\f21f",
|
||||||
"unread": "\f220",
|
"unlock": "\f220",
|
||||||
"up": "\f221",
|
"unmute": "\f221",
|
||||||
"user-filled": "\f222",
|
"unpin": "\f222",
|
||||||
"user-online": "\f223",
|
"unread": "\f223",
|
||||||
"user-stars": "\f224",
|
"up": "\f224",
|
||||||
"user": "\f225",
|
"user-filled": "\f225",
|
||||||
"video-outlined": "\f226",
|
"user-online": "\f226",
|
||||||
"video-stop": "\f227",
|
"user-stars": "\f227",
|
||||||
"video": "\f228",
|
"user": "\f228",
|
||||||
"view-once": "\f229",
|
"video-outlined": "\f229",
|
||||||
"voice-chat": "\f22a",
|
"video-stop": "\f22a",
|
||||||
"volume-1": "\f22b",
|
"video": "\f22b",
|
||||||
"volume-2": "\f22c",
|
"view-once": "\f22c",
|
||||||
"volume-3": "\f22d",
|
"voice-chat": "\f22d",
|
||||||
"warning": "\f22e",
|
"volume-1": "\f22e",
|
||||||
"web": "\f22f",
|
"volume-2": "\f22f",
|
||||||
"webapp": "\f230",
|
"volume-3": "\f230",
|
||||||
"word-wrap": "\f231",
|
"warning": "\f231",
|
||||||
"zoom-in": "\f232",
|
"web": "\f232",
|
||||||
"zoom-out": "\f233",
|
"webapp": "\f233",
|
||||||
|
"word-wrap": "\f234",
|
||||||
|
"zoom-in": "\f235",
|
||||||
|
"zoom-out": "\f236",
|
||||||
);
|
);
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@ -18,6 +18,9 @@ export type FontIconName =
|
|||||||
| 'arrow-right'
|
| 'arrow-right'
|
||||||
| 'ask-support'
|
| 'ask-support'
|
||||||
| 'attach'
|
| 'attach'
|
||||||
|
| 'auction-drop'
|
||||||
|
| 'auction-filled'
|
||||||
|
| 'auction-next-round'
|
||||||
| 'auction'
|
| 'auction'
|
||||||
| 'author-hidden'
|
| 'author-hidden'
|
||||||
| 'avatar-archived-chats'
|
| 'avatar-archived-chats'
|
||||||
|
|||||||
110
src/types/language.d.ts
vendored
110
src/types/language.d.ts
vendored
@ -1268,6 +1268,7 @@ export interface LangPair {
|
|||||||
'GiftInfoDescriptionFreeUpgrade': undefined;
|
'GiftInfoDescriptionFreeUpgrade': undefined;
|
||||||
'GiftInfoDescriptionUpgrade2': undefined;
|
'GiftInfoDescriptionUpgrade2': undefined;
|
||||||
'GiftInfoDescriptionUpgraded': undefined;
|
'GiftInfoDescriptionUpgraded': undefined;
|
||||||
|
'GiftInfoDescriptionRefunded': undefined;
|
||||||
'GiftInfoFrom': undefined;
|
'GiftInfoFrom': undefined;
|
||||||
'GiftInfoDate': undefined;
|
'GiftInfoDate': undefined;
|
||||||
'GiftInfoValue': undefined;
|
'GiftInfoValue': undefined;
|
||||||
@ -1745,6 +1746,8 @@ export interface LangPair {
|
|||||||
'StarGiftReasonDropOriginalDetails': undefined;
|
'StarGiftReasonDropOriginalDetails': undefined;
|
||||||
'GiftAnUpgradeButton': undefined;
|
'GiftAnUpgradeButton': undefined;
|
||||||
'GiftPrepaidUpgradeTransactionTitle': undefined;
|
'GiftPrepaidUpgradeTransactionTitle': undefined;
|
||||||
|
'StarGiftAuctionBidTransaction': undefined;
|
||||||
|
'StarGiftAuctionBidRefundedTransaction': undefined;
|
||||||
'ActionStarGiftPrepaidUpgradedYou': undefined;
|
'ActionStarGiftPrepaidUpgradedYou': undefined;
|
||||||
'UserNoteTitle': undefined;
|
'UserNoteTitle': undefined;
|
||||||
'UserNoteHint': undefined;
|
'UserNoteHint': undefined;
|
||||||
@ -1787,6 +1790,39 @@ export interface LangPair {
|
|||||||
'StarGiftPriceDecreaseInfoLink': undefined;
|
'StarGiftPriceDecreaseInfoLink': undefined;
|
||||||
'StarGiftUpgradeCostModalTitle': undefined;
|
'StarGiftUpgradeCostModalTitle': undefined;
|
||||||
'StarGiftUpgradeCostHint': undefined;
|
'StarGiftUpgradeCostHint': undefined;
|
||||||
|
'GiftRibbonAuction': undefined;
|
||||||
|
'GiftAuctionJoin': undefined;
|
||||||
|
'GiftAuctionLearnMore': undefined;
|
||||||
|
'GiftAuctionStarted': undefined;
|
||||||
|
'GiftAuctionEnds': undefined;
|
||||||
|
'GiftAuctionCurrentRound': undefined;
|
||||||
|
'GiftAuctionPlaceBid': undefined;
|
||||||
|
'GiftAuctionMinimumBid': undefined;
|
||||||
|
'GiftAuctionUntilNextRound': undefined;
|
||||||
|
'GiftAuctionLeft': undefined;
|
||||||
|
'GiftAuctionYourBidWillBe': undefined;
|
||||||
|
'GiftAuctionYoureWinning': undefined;
|
||||||
|
'GiftAuctionBalance': undefined;
|
||||||
|
'GiftAuctionInfoTitle': undefined;
|
||||||
|
'GiftAuctionInfoSubtitle': undefined;
|
||||||
|
'GiftAuctionInfoBidCarryoverTitle': undefined;
|
||||||
|
'GiftAuctionInfoMissedBiddersTitle': undefined;
|
||||||
|
'GiftAuctionInfoMissedBiddersSubtitle': undefined;
|
||||||
|
'GiftAuctionRecipient': undefined;
|
||||||
|
'GiftAuctionDate': undefined;
|
||||||
|
'GiftAuctionAcceptedBid': undefined;
|
||||||
|
'GiftAuctionCustomBidTitle': undefined;
|
||||||
|
'GiftAuctionCustomBidPlaceholder': undefined;
|
||||||
|
'GiftAuctionCustomBidButton': undefined;
|
||||||
|
'GiftAuctionBidPlacedTitle': undefined;
|
||||||
|
'GiftAuctionBidIncreasedTitle': undefined;
|
||||||
|
'GiftAuctionFinished': undefined;
|
||||||
|
'GiftAuctionEnded': undefined;
|
||||||
|
'GiftAuctionSoldOut': undefined;
|
||||||
|
'GiftAuctionChangeRecipientTitle': undefined;
|
||||||
|
'GiftAuctionAveragePrice': undefined;
|
||||||
|
'GiftAuctionTapToBidMore': undefined;
|
||||||
|
'StarGift': undefined;
|
||||||
'SettingsItemPrivacyPasskeys': undefined;
|
'SettingsItemPrivacyPasskeys': undefined;
|
||||||
'SettingsItemPrivacyOn': undefined;
|
'SettingsItemPrivacyOn': undefined;
|
||||||
'SettingsItemPrivacyOff': undefined;
|
'SettingsItemPrivacyOff': undefined;
|
||||||
@ -2645,6 +2681,15 @@ export interface LangPairWithVariables<V = LangVariable> {
|
|||||||
'ActionStarGiftLimitedRibbon': {
|
'ActionStarGiftLimitedRibbon': {
|
||||||
'total': V;
|
'total': V;
|
||||||
};
|
};
|
||||||
|
'ActionStarGiftAuctionWon': {
|
||||||
|
'cost': V;
|
||||||
|
};
|
||||||
|
'ActionStarGiftAuctionFor': {
|
||||||
|
'peer': V;
|
||||||
|
};
|
||||||
|
'ActionStarGiftAuctionBought': {
|
||||||
|
'cost': V;
|
||||||
|
};
|
||||||
'ActionSuggestedPhotoYou': {
|
'ActionSuggestedPhotoYou': {
|
||||||
'user': V;
|
'user': V;
|
||||||
};
|
};
|
||||||
@ -3120,6 +3165,43 @@ export interface LangPairWithVariables<V = LangVariable> {
|
|||||||
'StarGiftPriceDecreaseTimer': {
|
'StarGiftPriceDecreaseTimer': {
|
||||||
'timer': V;
|
'timer': V;
|
||||||
};
|
};
|
||||||
|
'GiftAuctionRoundValue': {
|
||||||
|
'current': V;
|
||||||
|
'total': V;
|
||||||
|
};
|
||||||
|
'GiftAuctionPlaceBidButton': {
|
||||||
|
'amount': V;
|
||||||
|
};
|
||||||
|
'GiftAuctionTimeLeft': {
|
||||||
|
'time': V;
|
||||||
|
};
|
||||||
|
'GiftAuctionAddToBid': {
|
||||||
|
'amount': V;
|
||||||
|
};
|
||||||
|
'GiftAuctionInfoBidCarryoverSubtitle': {
|
||||||
|
'count': V;
|
||||||
|
};
|
||||||
|
'GiftAuctionBoughtGiftHeader': {
|
||||||
|
'gift': V;
|
||||||
|
'giftNumber': V;
|
||||||
|
'round': V;
|
||||||
|
};
|
||||||
|
'GiftAuctionTopPosition': {
|
||||||
|
'position': V;
|
||||||
|
};
|
||||||
|
'GiftAuctionCustomBidDescription': {
|
||||||
|
'count': V;
|
||||||
|
};
|
||||||
|
'GiftAuctionBidPlacedMessage': {
|
||||||
|
'count': V;
|
||||||
|
};
|
||||||
|
'GiftAuctionChangeRecipientDescription': {
|
||||||
|
'oldPeer': V;
|
||||||
|
'newPeer': V;
|
||||||
|
};
|
||||||
|
'GiftAuctionWonNotification': {
|
||||||
|
'gift': V;
|
||||||
|
};
|
||||||
'SettingsPasskeyUsedAt': {
|
'SettingsPasskeyUsedAt': {
|
||||||
'date': V;
|
'date': V;
|
||||||
};
|
};
|
||||||
@ -3527,6 +3609,34 @@ export interface LangPairPluralWithVariables<V = LangVariable> {
|
|||||||
'list': V;
|
'list': V;
|
||||||
'count': V;
|
'count': V;
|
||||||
};
|
};
|
||||||
|
'GiftAuctionTopBidders': {
|
||||||
|
'count': V;
|
||||||
|
'gift': V;
|
||||||
|
'link': V;
|
||||||
|
};
|
||||||
|
'GiftAuctionDescription': {
|
||||||
|
'count': V;
|
||||||
|
'link': V;
|
||||||
|
};
|
||||||
|
'GiftAuctionTopWinners': {
|
||||||
|
'count': V;
|
||||||
|
};
|
||||||
|
'GiftAuctionInfoTopBiddersTitle': {
|
||||||
|
'count': V;
|
||||||
|
};
|
||||||
|
'GiftAuctionInfoTopBiddersSubtitle': {
|
||||||
|
'count': V;
|
||||||
|
};
|
||||||
|
'GiftAuctionItemsBought': {
|
||||||
|
'count': V;
|
||||||
|
'gift': V;
|
||||||
|
};
|
||||||
|
'GiftAuctionBoughtGiftsTitle': {
|
||||||
|
'count': V;
|
||||||
|
};
|
||||||
|
'GiftAuctionGifts': {
|
||||||
|
'count': V;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
export type RegularLangKey = keyof LangPair;
|
export type RegularLangKey = keyof LangPair;
|
||||||
export type RegularLangKeyWithVariables = keyof LangPairWithVariables;
|
export type RegularLangKeyWithVariables = keyof LangPairWithVariables;
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import { isUsernameValid } from './entities/username';
|
|||||||
export type DeepLinkMethod = 'resolve' | 'login' | 'passport' | 'settings' | 'join' | 'addstickers' | 'addemoji' |
|
export type DeepLinkMethod = 'resolve' | 'login' | 'passport' | 'settings' | 'join' | 'addstickers' | 'addemoji' |
|
||||||
'setlanguage' | 'addtheme' | 'confirmphone' | 'socks' | 'proxy' | 'privatepost' | 'bg' | 'share' | 'msg' | 'msg_url' |
|
'setlanguage' | 'addtheme' | 'confirmphone' | 'socks' | 'proxy' | 'privatepost' | 'bg' | 'share' | 'msg' | 'msg_url' |
|
||||||
'invoice' | 'addlist' | 'boost' | 'giftcode' | 'message' | 'premium_offer' | 'premium_multigift' | 'stars_topup'
|
'invoice' | 'addlist' | 'boost' | 'giftcode' | 'message' | 'premium_offer' | 'premium_multigift' | 'stars_topup'
|
||||||
| 'nft' | 'stars' | 'ton';
|
| 'nft' | 'stars' | 'ton' | 'stargift_auction';
|
||||||
|
|
||||||
interface PublicMessageLink {
|
interface PublicMessageLink {
|
||||||
type: 'publicMessageLink';
|
type: 'publicMessageLink';
|
||||||
@ -104,6 +104,11 @@ interface GiftUniqueLink {
|
|||||||
slug: string;
|
slug: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface GiftAuctionLink {
|
||||||
|
type: 'giftAuctionLink';
|
||||||
|
slug: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface StarsModalLink {
|
interface StarsModalLink {
|
||||||
type: 'stars';
|
type: 'stars';
|
||||||
}
|
}
|
||||||
@ -131,6 +136,7 @@ type DeepLink =
|
|||||||
PremiumMultigiftLink |
|
PremiumMultigiftLink |
|
||||||
ChatBoostLink |
|
ChatBoostLink |
|
||||||
GiftUniqueLink |
|
GiftUniqueLink |
|
||||||
|
GiftAuctionLink |
|
||||||
StarsModalLink |
|
StarsModalLink |
|
||||||
TonModalLink |
|
TonModalLink |
|
||||||
SettingsScreenLink;
|
SettingsScreenLink;
|
||||||
@ -269,6 +275,8 @@ function parseTgLink(url: URL) {
|
|||||||
return buildChatBoostLink({ username: queryParams.domain, id: queryParams.channel });
|
return buildChatBoostLink({ username: queryParams.domain, id: queryParams.channel });
|
||||||
case 'giftUniqueLink':
|
case 'giftUniqueLink':
|
||||||
return buildGiftUniqueLink({ slug: queryParams.slug });
|
return buildGiftUniqueLink({ slug: queryParams.slug });
|
||||||
|
case 'giftAuctionLink':
|
||||||
|
return buildGiftAuctionLink({ slug: queryParams.slug });
|
||||||
case 'stars':
|
case 'stars':
|
||||||
return { type: 'stars' } satisfies StarsModalLink;
|
return { type: 'stars' } satisfies StarsModalLink;
|
||||||
case 'ton':
|
case 'ton':
|
||||||
@ -384,6 +392,11 @@ function parseHttpLink(url: URL) {
|
|||||||
slug,
|
slug,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
case 'giftAuctionLink': {
|
||||||
|
return buildGiftAuctionLink({
|
||||||
|
slug: pathParams[1],
|
||||||
|
});
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -409,6 +422,7 @@ function getHttpDeepLinkType(
|
|||||||
if (method === 'm') return 'businessChatLink';
|
if (method === 'm') return 'businessChatLink';
|
||||||
if (method === 'boost') return 'chatBoostLink';
|
if (method === 'boost') return 'chatBoostLink';
|
||||||
if (method === 'nft') return 'giftUniqueLink';
|
if (method === 'nft') return 'giftUniqueLink';
|
||||||
|
if (method === 'auction') return 'giftAuctionLink';
|
||||||
if (method === 'c') {
|
if (method === 'c') {
|
||||||
if (queryParams.boost !== undefined) return 'chatBoostLink';
|
if (queryParams.boost !== undefined) return 'chatBoostLink';
|
||||||
return 'privateChannelLink';
|
return 'privateChannelLink';
|
||||||
@ -481,6 +495,8 @@ function getTgDeepLinkType(
|
|||||||
return 'chatBoostLink';
|
return 'chatBoostLink';
|
||||||
case 'nft':
|
case 'nft':
|
||||||
return 'giftUniqueLink';
|
return 'giftUniqueLink';
|
||||||
|
case 'stargift_auction':
|
||||||
|
return 'giftAuctionLink';
|
||||||
case 'stars':
|
case 'stars':
|
||||||
return 'stars';
|
return 'stars';
|
||||||
case 'ton':
|
case 'ton':
|
||||||
@ -710,6 +726,21 @@ function buildGiftUniqueLink(params: BuilderParams<GiftUniqueLink>): BuilderRetu
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildGiftAuctionLink(params: BuilderParams<GiftAuctionLink>): BuilderReturnType<GiftAuctionLink> {
|
||||||
|
const {
|
||||||
|
slug,
|
||||||
|
} = params;
|
||||||
|
|
||||||
|
if (!slug) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'giftAuctionLink',
|
||||||
|
slug,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function buildSettingsScreen(screenParam: string) {
|
function buildSettingsScreen(screenParam: string) {
|
||||||
switch (screenParam) {
|
switch (screenParam) {
|
||||||
case 'devices':
|
case 'devices':
|
||||||
|
|||||||
@ -79,6 +79,9 @@ export const processDeepLink = (url: string, linkContext?: LinkContext): boolean
|
|||||||
case 'giftUniqueLink':
|
case 'giftUniqueLink':
|
||||||
actions.openUniqueGiftBySlug({ slug: parsedLink.slug });
|
actions.openUniqueGiftBySlug({ slug: parsedLink.slug });
|
||||||
return true;
|
return true;
|
||||||
|
case 'giftAuctionLink':
|
||||||
|
actions.openGiftAuctionBySlug({ slug: parsedLink.slug });
|
||||||
|
return true;
|
||||||
case 'settings':
|
case 'settings':
|
||||||
if (!parsedLink.screen) {
|
if (!parsedLink.screen) {
|
||||||
actions.openLeftColumnContent({ contentKey: LeftColumnContent.Settings });
|
actions.openLeftColumnContent({ contentKey: LeftColumnContent.Settings });
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user