From 38d7cd0c5a9ee067342be68362aeab94d6162121 Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Tue, 23 Dec 2025 12:50:30 +0100 Subject: [PATCH] Star gift: Support auction (#6541) --- src/api/gramjs/apiBuilders/gifts.ts | 122 +++- src/api/gramjs/apiBuilders/messageActions.ts | 8 +- src/api/gramjs/apiBuilders/messageContent.ts | 16 + src/api/gramjs/apiBuilders/payments.ts | 3 +- src/api/gramjs/gramjsBuilders/index.ts | 14 + src/api/gramjs/methods/stars.ts | 47 ++ src/api/gramjs/updates/mtpUpdateHandler.ts | 17 + src/api/types/messageActions.ts | 3 + src/api/types/messages.ts | 8 +- src/api/types/payments.ts | 26 +- src/api/types/stars.ts | 71 +++ src/api/types/updates.ts | 23 +- src/assets/font-icons/auction-drop.svg | 1 + src/assets/font-icons/auction-filled.svg | 1 + src/assets/font-icons/auction-next-round.svg | 1 + src/assets/font-icons/user-stars.svg | 2 +- src/assets/localization/fallback.strings | 66 ++ src/bundles/stars.ts | 7 + src/components/common/helpers/gifts.ts | 49 ++ src/components/common/pickers/PickerModal.tsx | 1 + src/components/main/Main.tsx | 16 +- .../middle/message/ActionMessageText.tsx | 6 +- src/components/middle/message/WebPage.scss | 5 + src/components/middle/message/WebPage.tsx | 35 +- .../WebPageStarGiftAuction.module.scss | 69 ++ .../middle/message/WebPageStarGiftAuction.tsx | 103 +++ .../middle/message/_message-content.scss | 3 +- .../middle/message/actions/StarGift.tsx | 25 +- .../message/helpers/buildContentClassName.ts | 4 + .../middle/message/helpers/webpageType.ts | 16 +- src/components/modals/ModalContainer.tsx | 15 + .../modals/common/TableInfo.module.scss | 44 ++ src/components/modals/common/TableInfo.tsx | 64 ++ .../modals/common/TableInfoModal.module.scss | 47 -- .../modals/common/TableInfoModal.tsx | 29 +- .../modals/gift/GiftComposer.module.scss | 12 + src/components/modals/gift/GiftComposer.tsx | 69 +- .../modals/gift/GiftItem.module.scss | 9 + src/components/modals/gift/GiftItemStar.tsx | 76 ++- .../modals/gift/GiftModal.module.scss | 2 +- src/components/modals/gift/GiftModal.tsx | 24 +- .../GiftAuctionAcquiredModal.async.tsx | 14 + .../GiftAuctionAcquiredModal.module.scss | 50 ++ .../gift/auction/GiftAuctionAcquiredModal.tsx | 133 ++++ .../auction/GiftAuctionBidModal.async.tsx | 14 + .../auction/GiftAuctionBidModal.module.scss | 232 +++++++ .../gift/auction/GiftAuctionBidModal.tsx | 422 +++++++++++++ .../GiftAuctionChangeRecipientModal.async.tsx | 18 + ...iftAuctionChangeRecipientModal.module.scss | 14 + .../GiftAuctionChangeRecipientModal.tsx | 90 +++ .../auction/GiftAuctionInfoModal.async.tsx | 14 + .../auction/GiftAuctionInfoModal.module.scss | 53 ++ .../gift/auction/GiftAuctionInfoModal.tsx | 101 +++ .../gift/auction/GiftAuctionModal.async.tsx | 14 + .../gift/auction/GiftAuctionModal.module.scss | 82 +++ .../modals/gift/auction/GiftAuctionModal.tsx | 220 +++++++ .../gift/info/GiftInfoModal.module.scss | 16 +- .../modals/gift/info/GiftInfoModal.tsx | 5 +- .../modals/gift/upgrade/GiftUpgradeModal.tsx | 36 +- .../paidReaction/StarSlider.module.scss | 124 +++- .../modals/paidReaction/StarSlider.tsx | 324 ++++++++-- .../modals/stars/helpers/transaction.ts | 6 + .../transaction/StarsTransactionModal.tsx | 14 +- src/components/ui/TextTimer.tsx | 7 +- src/global/actions/api/payments.ts | 44 +- src/global/actions/api/stars.ts | 63 +- src/global/actions/apiUpdaters/misc.ts | 34 + src/global/actions/apiUpdaters/payments.ts | 52 +- src/global/actions/ui/stars.ts | 74 ++- src/global/helpers/payments.ts | 17 + src/global/reducers/gifts.ts | 78 ++- src/global/types/actions.ts | 48 ++ src/global/types/tabState.ts | 34 + src/hooks/useScrollNotch.ts | 21 +- src/lib/gramjs/tl/apiTl.ts | 2 + src/lib/gramjs/tl/static/api.json | 2 + src/styles/icons.css | 589 +++++++++--------- src/styles/icons.scss | 579 ++++++++--------- src/styles/icons.woff | Bin 38924 -> 39544 bytes src/styles/icons.woff2 | Bin 32428 -> 32932 bytes src/types/icons/font.ts | 3 + src/types/language.d.ts | 110 ++++ src/util/deepLinkParser.ts | 33 +- src/util/deeplink.ts | 3 + 84 files changed, 4101 insertions(+), 847 deletions(-) create mode 100644 src/assets/font-icons/auction-drop.svg create mode 100644 src/assets/font-icons/auction-filled.svg create mode 100644 src/assets/font-icons/auction-next-round.svg create mode 100644 src/components/middle/message/WebPageStarGiftAuction.module.scss create mode 100644 src/components/middle/message/WebPageStarGiftAuction.tsx create mode 100644 src/components/modals/common/TableInfo.module.scss create mode 100644 src/components/modals/common/TableInfo.tsx create mode 100644 src/components/modals/gift/auction/GiftAuctionAcquiredModal.async.tsx create mode 100644 src/components/modals/gift/auction/GiftAuctionAcquiredModal.module.scss create mode 100644 src/components/modals/gift/auction/GiftAuctionAcquiredModal.tsx create mode 100644 src/components/modals/gift/auction/GiftAuctionBidModal.async.tsx create mode 100644 src/components/modals/gift/auction/GiftAuctionBidModal.module.scss create mode 100644 src/components/modals/gift/auction/GiftAuctionBidModal.tsx create mode 100644 src/components/modals/gift/auction/GiftAuctionChangeRecipientModal.async.tsx create mode 100644 src/components/modals/gift/auction/GiftAuctionChangeRecipientModal.module.scss create mode 100644 src/components/modals/gift/auction/GiftAuctionChangeRecipientModal.tsx create mode 100644 src/components/modals/gift/auction/GiftAuctionInfoModal.async.tsx create mode 100644 src/components/modals/gift/auction/GiftAuctionInfoModal.module.scss create mode 100644 src/components/modals/gift/auction/GiftAuctionInfoModal.tsx create mode 100644 src/components/modals/gift/auction/GiftAuctionModal.async.tsx create mode 100644 src/components/modals/gift/auction/GiftAuctionModal.module.scss create mode 100644 src/components/modals/gift/auction/GiftAuctionModal.tsx diff --git a/src/api/gramjs/apiBuilders/gifts.ts b/src/api/gramjs/apiBuilders/gifts.ts index c95815107..08601c746 100644 --- a/src/api/gramjs/apiBuilders/gifts.ts +++ b/src/api/gramjs/apiBuilders/gifts.ts @@ -1,6 +1,7 @@ import { Api as GramJs } from '../../../lib/gramjs'; import type { + ApiAuctionBidLevel, ApiDisallowedGiftsSettings, ApiInputSavedStarGift, ApiSavedStarGift, @@ -8,10 +9,14 @@ import type { ApiStarGiftAttribute, ApiStarGiftAttributeCounter, ApiStarGiftAttributeId, + ApiStarGiftAuctionAcquiredGift, + ApiStarGiftAuctionState, + ApiStarGiftAuctionUserState, ApiStarGiftCollection, ApiStarGiftUpgradePreview, ApiStarGiftUpgradePrice, ApiTypeResaleStarGifts, + ApiTypeStarGiftAuctionState, } from '../../types'; import { int2hex } from '../../../util/colors'; @@ -20,6 +25,7 @@ import { buildApiChatFromPreview } from '../apiBuilders/chats'; import { addDocumentToLocalDb } from '../helpers/localDb'; import { buildApiFormattedText } from './common'; import { buildApiCurrencyAmount } from './payments'; +import { buildApiPeerId } from './peers'; import { getApiChatIdFromMtpPeer } from './peers'; import { buildStickerFromDocument } from './symbols'; import { buildApiUser } from './users'; @@ -57,7 +63,7 @@ export function buildApiStarGift(starGift: GramJs.TypeStarGift): ApiStarGift { const { id, limited, stars, availabilityRemains, availabilityTotal, convertStars, firstSaleDate, lastSaleDate, soldOut, birthday, upgradeStars, resellMinStars, title, availabilityResale, releasedBy, - requirePremium, limitedPerUser, perUserTotal, perUserRemains, lockedUntilDate, + requirePremium, limitedPerUser, perUserTotal, perUserRemains, lockedUntilDate, auction, giftsPerRound, background, } = starGift; addDocumentToLocalDb(starGift.sticker); @@ -87,6 +93,13 @@ export function buildApiStarGift(starGift: GramJs.TypeStarGift): ApiStarGift { perUserTotal, perUserRemains, 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 { const { - gift, date, convertStars, fromId, message, msgId, nameHidden, unsaved, upgradeStars, transferStars, canUpgrade, - savedId, canExportAt, pinnedToTop, canResellAt, canTransferAt, prepaidUpgradeHash, dropOriginalDetailsStars, + gift, date, convertStars, fromId, message, msgId, nameHidden, unsaved, refunded, upgradeStars, transferStars, + canUpgrade, savedId, canExportAt, pinnedToTop, canResellAt, canTransferAt, prepaidUpgradeHash, + dropOriginalDetailsStars, } = userStarGift; const inputGift: ApiInputSavedStarGift | undefined = savedId && peerId @@ -176,6 +190,7 @@ export function buildApiSavedStarGift(userStarGift: GramJs.SavedStarGift, peerId messageId: msgId, isNameHidden: nameHidden, isUnsaved: unsaved, + isRefunded: refunded, canUpgrade, alreadyPaidUpgradeStars: toJSNumber(upgradeStars), transferStars: toJSNumber(transferStars), @@ -334,3 +349,104 @@ export function buildApiStarGiftUpgradePreview( 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, + }; +} diff --git a/src/api/gramjs/apiBuilders/messageActions.ts b/src/api/gramjs/apiBuilders/messageActions.ts index a66aa7b31..caf6ab360 100644 --- a/src/api/gramjs/apiBuilders/messageActions.ts +++ b/src/api/gramjs/apiBuilders/messageActions.ts @@ -390,8 +390,9 @@ export function buildApiMessageAction(action: GramJs.TypeMessageAction): ApiMess } if (action instanceof GramJs.MessageActionStarGift) { const { - nameHidden, saved, converted, upgraded, refunded, canUpgrade, prepaidUpgrade, gift, message, convertStars, - upgradeMsgId, giftMsgId, upgradeStars, fromId, peer, savedId, prepaidUpgradeHash, + nameHidden, saved, converted, upgraded, refunded, canUpgrade, prepaidUpgrade, auctionAcquired, + gift, message, convertStars, upgradeMsgId, giftMsgId, upgradeStars, fromId, peer, savedId, + prepaidUpgradeHash, toId, giftNum, } = action; const starGift = buildApiStarGift(gift); @@ -407,6 +408,7 @@ export function buildApiMessageAction(action: GramJs.TypeMessageAction): ApiMess isRefunded: refunded, canUpgrade, isPrepaidUpgrade: prepaidUpgrade, + isAuctionAcquired: auctionAcquired, gift: starGift, message: message && buildApiFormattedText(message), starsToConvert: toJSNumber(convertStars), @@ -417,6 +419,8 @@ export function buildApiMessageAction(action: GramJs.TypeMessageAction): ApiMess peerId: peer && getApiChatIdFromMtpPeer(peer), savedId: savedId !== undefined ? buildApiPeerId(savedId, 'user') : undefined, prepaidUpgradeHash, + toId: toId && getApiChatIdFromMtpPeer(toId), + giftNumber: giftNum, }; } if (action instanceof GramJs.MessageActionStarGiftUnique) { diff --git a/src/api/gramjs/apiBuilders/messageContent.ts b/src/api/gramjs/apiBuilders/messageContent.ts index 266d48f7e..1754e040c 100644 --- a/src/api/gramjs/apiBuilders/messageContent.ts +++ b/src/api/gramjs/apiBuilders/messageContent.ts @@ -24,6 +24,7 @@ import type { ApiVoice, ApiWebDocument, ApiWebPage, + ApiWebPageAuctionData, ApiWebPageStickerData, ApiWebPageStoryData, BoughtPaidMedia, @@ -863,11 +864,16 @@ export function buildWebPage(webPage: GramJs.TypeWebPage): ApiWebPage | undefine } let story: ApiWebPageStoryData | undefined; let gift: ApiStarGiftUnique | undefined; + let auction: ApiWebPageAuctionData | undefined; let stickers: ApiWebPageStickerData | undefined; const attributeStory = attributes ?.find((a): a is GramJs.WebPageAttributeStory => a instanceof GramJs.WebPageAttributeStory); const attributeGift = attributes ?.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) { const peerId = getApiChatIdFromMtpPeer(attributeStory.peer); story = { @@ -883,6 +889,15 @@ export function buildWebPage(webPage: GramJs.TypeWebPage): ApiWebPage | undefine const starGift = buildApiStarGift(attributeGift.gift); 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 => ( a instanceof GramJs.WebPageAttributeStickerSet )); @@ -914,6 +929,7 @@ export function buildWebPage(webPage: GramJs.TypeWebPage): ApiWebPage | undefine audio, story, gift, + auction, stickers, }; } diff --git a/src/api/gramjs/apiBuilders/payments.ts b/src/api/gramjs/apiBuilders/payments.ts index ea74ed375..e7cf2604f 100644 --- a/src/api/gramjs/apiBuilders/payments.ts +++ b/src/api/gramjs/apiBuilders/payments.ts @@ -553,7 +553,7 @@ export function buildApiStarsTransaction(transaction: GramJs.StarsTransaction): const { date, id, peer, amount, description, photo, title, refund, extendedMedia, failed, msgId, pending, gift, reaction, subscriptionPeriod, stargift, giveawayPostId, starrefCommissionPermille, stargiftUpgrade, paidMessages, - stargiftResale, postsSearch, stargiftPrepaidUpgrade, stargiftDropOriginalDetails, + stargiftResale, postsSearch, stargiftPrepaidUpgrade, stargiftDropOriginalDetails, stargiftAuctionBid, } = transaction; if (photo) { @@ -595,6 +595,7 @@ export function buildApiStarsTransaction(transaction: GramJs.StarsTransaction): isPostsSearch: postsSearch, isDropOriginalDetails: stargiftDropOriginalDetails, isPrepaidUpgrade: stargiftPrepaidUpgrade, + isStarGiftAuctionBid: stargiftAuctionBid, }; } diff --git a/src/api/gramjs/gramjsBuilders/index.ts b/src/api/gramjs/gramjsBuilders/index.ts index 94edb0ffe..e32b2af5e 100644 --- a/src/api/gramjs/gramjsBuilders/index.ts +++ b/src/api/gramjs/gramjsBuilders/index.ts @@ -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': default: { const purpose = buildInputStorePaymentPurpose(invoice.purpose); diff --git a/src/api/gramjs/methods/stars.ts b/src/api/gramjs/methods/stars.ts index 92e086d7e..1b504f76e 100644 --- a/src/api/gramjs/methods/stars.ts +++ b/src/api/gramjs/methods/stars.ts @@ -18,6 +18,8 @@ import { buildApiResaleGifts, buildApiSavedStarGift, buildApiStarGift, + buildApiStarGiftAuctionAcquiredGift, + buildApiStarGiftAuctionState, buildApiStarGiftCollection, buildApiStarGiftUpgradePreview, buildInputResaleGiftsAttributes, @@ -412,6 +414,51 @@ export async function fetchStarGiftUpgradePreview({ 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({ inputSavedGift, shouldKeepOriginalDetails, diff --git a/src/api/gramjs/updates/mtpUpdateHandler.ts b/src/api/gramjs/updates/mtpUpdateHandler.ts index b8d8aeb47..cb72bd3a9 100644 --- a/src/api/gramjs/updates/mtpUpdateHandler.ts +++ b/src/api/gramjs/updates/mtpUpdateHandler.ts @@ -31,6 +31,7 @@ import { buildApiFormattedText, buildApiPhoto, buildApiUsernames, buildPrivacyRules, } from '../apiBuilders/common'; +import { buildApiStarGiftAuctionUserState, buildApiTypeStarGiftAuctionState } from '../apiBuilders/gifts'; import { omitVirtualClassFields } from '../apiBuilders/helpers'; import { buildApiMessageExtendedMediaPreview, @@ -1095,6 +1096,22 @@ export function updater(update: Update) { '@type': 'updateStarsBalance', 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) { sendApiUpdate({ '@type': 'updatePaidReactionPrivacy', diff --git a/src/api/types/messageActions.ts b/src/api/types/messageActions.ts index 9ff21fa3c..adf0d2ab9 100644 --- a/src/api/types/messageActions.ts +++ b/src/api/types/messageActions.ts @@ -243,6 +243,7 @@ export interface ApiMessageActionStarGift extends ActionMediaType { isRefunded?: true; canUpgrade?: true; isPrepaidUpgrade?: true; + isAuctionAcquired?: true; gift: ApiStarGiftRegular; message?: ApiFormattedText; starsToConvert?: number; @@ -253,6 +254,8 @@ export interface ApiMessageActionStarGift extends ActionMediaType { peerId?: string; savedId?: string; prepaidUpgradeHash?: string; + toId?: string; + giftNumber?: number; } export interface ApiMessageActionStarGiftUnique extends ActionMediaType { diff --git a/src/api/types/messages.ts b/src/api/types/messages.ts index 2602c3123..be7c1bb8a 100644 --- a/src/api/types/messages.ts +++ b/src/api/types/messages.ts @@ -10,7 +10,7 @@ import type { ApiLabeledPrice, } from './payments'; import type { ApiTypePeerColor } from './peers'; -import type { ApiStarGiftUnique, ApiTypeCurrencyAmount } from './stars'; +import type { ApiStarGiftRegular, ApiStarGiftUnique, ApiTypeCurrencyAmount } from './stars'; import type { ApiMessageStoryData, ApiStory, ApiWebPageStickerData, ApiWebPageStoryData, } from './stories'; @@ -394,10 +394,16 @@ export interface ApiWebPageFull { video?: ApiVideo; story?: ApiWebPageStoryData; gift?: ApiStarGiftUnique; + auction?: ApiWebPageAuctionData; stickers?: ApiWebPageStickerData; hasLargeMedia?: boolean; } +export type ApiWebPageAuctionData = { + gift: ApiStarGiftRegular; + endDate: number; +}; + export type ApiWebPage = ApiWebPagePending | ApiWebPageEmpty | ApiWebPageFull; /** diff --git a/src/api/types/payments.ts b/src/api/types/payments.ts index f3460a76f..07490398d 100644 --- a/src/api/types/payments.ts +++ b/src/api/types/payments.ts @@ -412,11 +412,22 @@ export type ApiInputInvoiceStarGiftPrepaidUpgrade = { 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 | ApiInputInvoiceGiftCode | ApiInputInvoicePremiumGiftStars | ApiInputInvoiceStars | ApiInputInvoiceStarsGift | ApiInputInvoiceStarsGiveaway | ApiInputInvoiceStarGift | ApiInputInvoiceChatInviteSubscription | ApiInputInvoiceStarGiftUpgrade | ApiInputInvoiceStarGiftTransfer | ApiInputInvoiceStarGiftResale - | ApiInputInvoiceStarGiftDropOriginalDetails | ApiInputInvoiceStarGiftPrepaidUpgrade; + | ApiInputInvoiceStarGiftDropOriginalDetails | ApiInputInvoiceStarGiftPrepaidUpgrade + | ApiInputInvoiceStarGiftAuctionBid; /* Used for Invoice request */ export type ApiRequestInputInvoiceMessage = { @@ -497,12 +508,23 @@ export type ApiRequestInputInvoiceStarGiftPrepaidUpgrade = { hash: string; }; +export type ApiRequestInputInvoiceStarGiftAuctionBid = { + type: 'stargiftAuctionBid'; + giftId: string; + bidAmount: number; + peer?: ApiPeer; + message?: ApiFormattedText; + shouldHideName?: boolean; + isUpdateBid?: boolean; +}; + export type ApiRequestInputInvoice = ApiRequestInputInvoiceMessage | ApiRequestInputInvoiceSlug | ApiRequestInputInvoiceGiveaway | ApiRequestInputInvoiceStars | ApiRequestInputInvoiceStarsGiveaway | ApiRequestInputInvoiceChatInviteSubscription | ApiRequestInputInvoiceStarGift | ApiRequestInputInvoiceStarGiftUpgrade | ApiRequestInputInvoiceStarGiftTransfer | ApiRequestInputInvoicePremiumGiftStars | ApiRequestInputInvoiceStarGiftResale - | ApiRequestInputInvoiceStarGiftDropOriginalDetails | ApiRequestInputInvoiceStarGiftPrepaidUpgrade; + | ApiRequestInputInvoiceStarGiftDropOriginalDetails | ApiRequestInputInvoiceStarGiftPrepaidUpgrade + | ApiRequestInputInvoiceStarGiftAuctionBid; export interface ApiUniqueStarGiftValueInfo { isLastSaleOnFragment?: true; diff --git a/src/api/types/stars.ts b/src/api/types/stars.ts index ca1ab9f6d..f89f1e0f5 100644 --- a/src/api/types/stars.ts +++ b/src/api/types/stars.ts @@ -27,6 +27,15 @@ export interface ApiStarGiftRegular { perUserTotal?: number; perUserRemains?: number; lockedUntilDate?: number; + isAuction?: true; + giftsPerRound?: number; + background?: ApiStarGiftBackground; +} + +export interface ApiStarGiftBackground { + centerColor: string; + edgeColor: string; + textColor: string; } export interface ApiStarGiftUnique { @@ -103,6 +112,7 @@ export interface ApiStarGiftUpgradePreview { export interface ApiSavedStarGift { isNameHidden?: boolean; isUnsaved?: boolean; + isRefunded?: boolean; fromId?: string; date: number; gift: ApiStarGift; @@ -259,6 +269,7 @@ export interface ApiStarsTransaction { isPostsSearch?: true; isDropOriginalDetails?: true; isPrepaidUpgrade?: true; + isStarGiftAuctionBid?: true; } export interface ApiStarsSubscription { @@ -315,3 +326,63 @@ export interface ApiStarsRating { stars: 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; +} diff --git a/src/api/types/updates.ts b/src/api/types/updates.ts index add51f3d7..04b81e5f7 100644 --- a/src/api/types/updates.ts +++ b/src/api/types/updates.ts @@ -45,7 +45,7 @@ import type { } from './misc'; import type { ApiEmojiStatusType, ApiPeerSettings } from './peers'; 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 { ApiUser, ApiUserFullInfo, ApiUserStatus, @@ -834,6 +834,18 @@ export type ApiUpdateStarsBalance = { balance: ApiTypeCurrencyAmount; }; +export type ApiUpdateStarGiftAuctionState = { + '@type': 'updateStarGiftAuctionState'; + giftId: string; + state: ApiTypeStarGiftAuctionState; +}; + +export type ApiUpdateStarGiftAuctionUserState = { + '@type': 'updateStarGiftAuctionUserState'; + giftId: string; + userState: ApiStarGiftAuctionUserState; +}; + export type ApiUpdateDeleteProfilePhoto = { '@type': 'updateDeleteProfilePhoto'; peerId: string; @@ -915,10 +927,11 @@ export type ApiUpdate = ( ApiRequestReconnectApi | ApiRequestSync | ApiUpdateFetchingDifference | ApiUpdateChannelMessages | ApiUpdateStealthMode | ApiUpdateAttachMenuBots | ApiUpdateNewAuthorization | ApiUpdateGroupInvitePrivacyForbidden | ApiUpdateViewForumAsMessages | ApiUpdateSavedDialogPinned | ApiUpdatePinnedSavedDialogIds | ApiUpdateChatLastMessage | - ApiUpdateDeleteSavedHistory | ApiUpdatePremiumFloodWait | ApiUpdateStarsBalance | ApiUpdateBotCommands | - ApiUpdateQuickReplyMessage | ApiUpdateQuickReplies | ApiDeleteQuickReply | ApiUpdateDeleteQuickReplyMessages | - ApiUpdateDeleteProfilePhoto | ApiUpdateNewProfilePhoto | ApiUpdateEntities | ApiUpdatePaidReactionPrivacy | - ApiUpdateLangPackTooLong | ApiUpdateLangPack | ApiUpdateNotSupportedInFrozenAccountError + ApiUpdateDeleteSavedHistory | ApiUpdatePremiumFloodWait | ApiUpdateStarsBalance | ApiUpdateStarGiftAuctionState + | ApiUpdateStarGiftAuctionUserState | ApiUpdateBotCommands | ApiUpdateQuickReplyMessage | ApiUpdateQuickReplies + | ApiDeleteQuickReply | ApiUpdateDeleteQuickReplyMessages | ApiUpdateDeleteProfilePhoto | ApiUpdateNewProfilePhoto + | ApiUpdateEntities | ApiUpdatePaidReactionPrivacy | ApiUpdateLangPackTooLong | ApiUpdateLangPack + | ApiUpdateNotSupportedInFrozenAccountError ); export type OnApiUpdate = (update: ApiUpdate) => void; diff --git a/src/assets/font-icons/auction-drop.svg b/src/assets/font-icons/auction-drop.svg new file mode 100644 index 000000000..41c485da5 --- /dev/null +++ b/src/assets/font-icons/auction-drop.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/font-icons/auction-filled.svg b/src/assets/font-icons/auction-filled.svg new file mode 100644 index 000000000..1859bac65 --- /dev/null +++ b/src/assets/font-icons/auction-filled.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/font-icons/auction-next-round.svg b/src/assets/font-icons/auction-next-round.svg new file mode 100644 index 000000000..bb881d5b7 --- /dev/null +++ b/src/assets/font-icons/auction-next-round.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/font-icons/user-stars.svg b/src/assets/font-icons/user-stars.svg index 08943452a..cd4c26bdb 100644 --- a/src/assets/font-icons/user-stars.svg +++ b/src/assets/font-icons/user-stars.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/assets/localization/fallback.strings b/src/assets/localization/fallback.strings index ef119ff6d..52df59eec 100644 --- a/src/assets/localization/fallback.strings +++ b/src/assets/localization/fallback.strings @@ -1513,6 +1513,7 @@ "GiftInfoDescriptionUpgrade2" = "Upgrade this gift to turn it to a unique collectible."; "GiftInfoPeerDescriptionFreeUpgradeOut" = "{peer} can turn this gift 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"; "GiftInfoDate" = "Date"; "GiftInfoValue" = "Value"; @@ -1929,6 +1930,9 @@ "ActionStarGiftUniqueBackdrop" = "Backdrop"; "ActionStarGiftUniqueSymbol" = "Symbol"; "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."; "ActionSuggestedPhoto" = "{user} suggests this photo for your Telegram profile."; "ActionSuggestedPhotoButton" = "View Photo"; @@ -2343,6 +2347,8 @@ "StarGiftReasonDropOriginalDetails" = "Removed Description"; "GiftAnUpgradeButton" = "Gift an Upgrade"; "GiftPrepaidUpgradeTransactionTitle" = "Gift Upgrade"; +"StarGiftAuctionBidTransaction" = "Auction Bid"; +"StarGiftAuctionBidRefundedTransaction" = "Refunded Auction Bid"; "ActionStarGiftPrepaidUpgraded" = "{user} turned the gift into a unique collectible"; "ActionStarGiftPrepaidUpgradedYou" = "You turned the gift into a unique collectible"; "UserNoteTitle" = "Notes"; @@ -2405,6 +2411,66 @@ "StarGiftUpgradeCostModalTitle" = "Upgrade Cost"; "StarGiftUpgradeCostHint" = "Users who upgrade their gifts first get collectibles with lower numbers."; "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"; "SettingsItemPrivacyOn" = "Enabled"; "SettingsItemPrivacyOff" = "Disabled"; diff --git a/src/bundles/stars.ts b/src/bundles/stars.ts index 755488a0b..5a29a7098 100644 --- a/src/bundles/stars.ts +++ b/src/bundles/stars.ts @@ -1,3 +1,5 @@ +/* eslint-disable @stylistic/max-len */ + export { default as StarsGiftModal } from '../components/modals/stars/gift/StarsGiftModal'; export { default as StarsGiftingPickerModal } from '../components/main/premium/StarsGiftingPickerModal'; 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 GiftResalePriceComposerModal } from '../components/modals/gift/resale/GiftResalePriceComposerModal'; 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 GiftStatusInfoModal } from '../components/modals/gift/status/GiftStatusInfoModal'; export { default as GiftWithdrawModal } from '../components/modals/gift/withdraw/GiftWithdrawModal'; diff --git a/src/components/common/helpers/gifts.ts b/src/components/common/helpers/gifts.ts index f8009c52d..e360ae265 100644 --- a/src/components/common/helpers/gifts.ts +++ b/src/components/common/helpers/gifts.ts @@ -15,6 +15,12 @@ export type GiftAttributes = { backdrop?: ApiStarGiftAttributeBackdrop; }; +export type GiftPreviewAttributes = { + model: ApiStarGiftAttributeModel; + pattern: ApiStarGiftAttributePattern; + backdrop: ApiStarGiftAttributeBackdrop; +}; + export function getStickerFromGift(gift: ApiStarGift): ApiSticker | undefined { if (gift.type === 'starGift') { return gift.sticker; @@ -52,3 +58,46 @@ function getGiftAttributesFromList(attributes: ApiStarGiftAttribute[]) { 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, + }; +} diff --git a/src/components/common/pickers/PickerModal.tsx b/src/components/common/pickers/PickerModal.tsx index 9d6fb8934..748bd16e5 100644 --- a/src/components/common/pickers/PickerModal.tsx +++ b/src/components/common/pickers/PickerModal.tsx @@ -42,6 +42,7 @@ const PickerModal = ({ containerRef: dialogRef, selector: `.modal-content ${itemsContainerSelector}`, isBottomNotch: true, + shouldHideTopNotch: true, }, [modalProps.isOpen]); return ( diff --git a/src/components/main/Main.tsx b/src/components/main/Main.tsx index 8a127aee5..8948d4481 100644 --- a/src/components/main/Main.tsx +++ b/src/components/main/Main.tsx @@ -8,7 +8,7 @@ import { import { addExtraClass } from '../../lib/teact/teact-dom'; 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 { BASE_EMOJI_KEYWORD_LANG, DEBUG, FOLDERS_POSITION_LEFT, INACTIVE_MARKER } from '../../config'; @@ -145,6 +145,7 @@ type StateProps = { isAccountFrozen?: boolean; isAppConfigLoaded?: boolean; isFoldersSidebarShown: boolean; + activeGiftAuction?: ApiStarGiftAuctionState; }; const APP_OUTDATED_TIMEOUT_MS = 5 * 60 * 1000; // 5 min @@ -198,6 +199,7 @@ const Main = ({ isAccountFrozen, isAppConfigLoaded, isFoldersSidebarShown, + activeGiftAuction, }: OwnProps & StateProps) => { const { initMain, @@ -258,6 +260,7 @@ const Main = ({ loadAllStories, loadAllHiddenStories, loadContentSettings, + loadActiveGiftAuction, loadPromoData, } = getActions(); @@ -439,6 +442,15 @@ const Main = ({ }); }, [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 useLayoutEffect(() => { const container = containerRef.current!; @@ -635,6 +647,7 @@ export default memo(withGlobal( payment, limitReachedModal, deleteFolderDialogModal, + activeGiftAuction, } = selectTabState(global); const { wasTimeFormatSetManually, foldersPosition } = selectSharedSettings(global); @@ -693,6 +706,7 @@ export default memo(withGlobal( isAccountFrozen, isAppConfigLoaded: global.isAppConfigLoaded, isFoldersSidebarShown: foldersPosition === FOLDERS_POSITION_LEFT && !isMobile && selectAreFoldersPresent(global), + activeGiftAuction, }; }, )(Main)); diff --git a/src/components/middle/message/ActionMessageText.tsx b/src/components/middle/message/ActionMessageText.tsx index df6e86d32..e0359d973 100644 --- a/src/components/middle/message/ActionMessageText.tsx +++ b/src/components/middle/message/ActionMessageText.tsx @@ -556,7 +556,7 @@ const ActionMessageText = ({ case 'starGift': { const { - gift, alreadyPaidUpgradeStars, peerId, savedId, fromId, isPrepaidUpgrade, + gift, alreadyPaidUpgradeStars, peerId, savedId, fromId, isPrepaidUpgrade, isAuctionAcquired, } = action; const isToChannel = Boolean(peerId && savedId); @@ -572,6 +572,10 @@ const ActionMessageText = ({ const starsAmount = gift.stars + (alreadyPaidUpgradeStars || 0); const cost = renderStrong(formatStarsAsText(lang, starsAmount)); + if (isAuctionAcquired) { + return lang('ActionStarGiftAuctionWon', { cost }, { withNodes: true }); + } + if (isPrepaidUpgrade && gift.upgradeStars) { const upgradeCost = renderStrong(formatStarsAsText(lang, gift.upgradeStars)); diff --git a/src/components/middle/message/WebPage.scss b/src/components/middle/message/WebPage.scss index 7c6f4df67..0a165ce29 100644 --- a/src/components/middle/message/WebPage.scss +++ b/src/components/middle/message/WebPage.scss @@ -72,6 +72,11 @@ opacity: 0.85; background-color: transparent !important; } + + .icon { + margin-inline-end: 0.25rem; + font-size: 1rem !important; + } } .with-gift &--quick-button { diff --git a/src/components/middle/message/WebPage.tsx b/src/components/middle/message/WebPage.tsx index ccbf38bac..c6eb9b746 100644 --- a/src/components/middle/message/WebPage.tsx +++ b/src/components/middle/message/WebPage.tsx @@ -13,7 +13,7 @@ import buildClassName from '../../../util/buildClassName'; import { tryParseDeepLink } from '../../../util/deepLinkParser'; import trimText from '../../../util/trimText'; import renderText from '../../common/helpers/renderText'; -import { getWebpageButtonLangKey } from './helpers/webpageType'; +import { getWebpageButtonIcon, getWebpageButtonLangKey } from './helpers/webpageType'; import useDynamicColorListener from '../../../hooks/stickers/useDynamicColorListener'; import useEnsureStory from '../../../hooks/useEnsureStory'; @@ -23,6 +23,7 @@ import useLastCallback from '../../../hooks/useLastCallback'; import Audio from '../../common/Audio'; import Document from '../../common/Document'; import EmojiIconBackground from '../../common/embedded/EmojiIconBackground'; +import Icon from '../../common/icons/Icon'; import PeerColorWrapper from '../../common/PeerColorWrapper'; import SafeLink from '../../common/SafeLink'; import StickerView from '../../common/StickerView'; @@ -30,6 +31,7 @@ import Button from '../../ui/Button'; import BaseStory from './BaseStory'; import Photo from './Photo'; import Video from './Video'; +import WebPageStarGiftAuction from './WebPageStarGiftAuction'; import WebPageUniqueGift from './WebPageUniqueGift'; import './WebPage.scss'; @@ -37,6 +39,7 @@ import './WebPage.scss'; const MAX_TEXT_LENGTH = 170; // symbols const WEBPAGE_STORY_TYPE = 'telegram_story'; const WEBPAGE_GIFT_TYPE = 'telegram_nft'; +const WEBPAGE_AUCTION_TYPE = 'telegram_auction'; const STICKER_SIZE = 80; const EMOJI_SIZE = 38; @@ -145,11 +148,14 @@ const WebPage: FC = ({ const { mediaSize } = messageWebPage; const isStory = type === WEBPAGE_STORY_TYPE; const isGift = type === WEBPAGE_GIFT_TYPE; + const isAuction = type === WEBPAGE_AUCTION_TYPE; const isExpiredStory = story && 'isDeleted' in story; 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 quickButtonIcon = getWebpageButtonIcon(resultType); const truncatedDescription = trimText(description, MAX_TEXT_LENGTH); const isArticle = Boolean(truncatedDescription || title || siteName); @@ -167,20 +173,21 @@ const WebPage: FC = ({ !isArticle && 'no-article', document && 'with-document', quickButtonTitle && 'with-quick-button', - isGift && 'with-gift', + (isGift || isAuction) && 'with-gift', ); - function renderQuickButton(caption: string) { + function renderQuickButton() { return ( ); } @@ -195,7 +202,7 @@ const WebPage: FC = ({
{backgroundEmojiId && ( @@ -215,6 +222,14 @@ const WebPage: FC = ({ onClick={handleOpenTelegramLink} /> )} + {isAuction && webPage.auction && ( + + )} {isArticle && (
= ({ {title && (

{renderText(title)}

)} - {truncatedDescription && !isGift && ( + {truncatedDescription && !isGift && !isAuction && (

{renderText(truncatedDescription, ['emoji', 'br'])}

)}
)} - {photo && !isGift && !video && !document && ( + {photo && !isGift && !isAuction && !video && !document && ( = ({
)} - {quickButtonTitle && renderQuickButton(quickButtonTitle)} + {quickButtonTitle && renderQuickButton()} ); }; diff --git a/src/components/middle/message/WebPageStarGiftAuction.module.scss b/src/components/middle/message/WebPageStarGiftAuction.module.scss new file mode 100644 index 000000000..11c69ceed --- /dev/null +++ b/src/components/middle/message/WebPageStarGiftAuction.module.scss @@ -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); +} diff --git a/src/components/middle/message/WebPageStarGiftAuction.tsx b/src/components/middle/message/WebPageStarGiftAuction.tsx new file mode 100644 index 000000000..aa3d21ecb --- /dev/null +++ b/src/components/middle/message/WebPageStarGiftAuction.tsx @@ -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(); + 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 ( +
+ +
+ {isFinished ? lang('GiftAuctionFinished') : } +
+ + + +
{title}
+
{subtitleText}
+
+ ); +}; + +export default memo(WebPageStarGiftAuction); diff --git a/src/components/middle/message/_message-content.scss b/src/components/middle/message/_message-content.scss index 0420b4d1e..cc289c437 100644 --- a/src/components/middle/message/_message-content.scss +++ b/src/components/middle/message/_message-content.scss @@ -27,7 +27,8 @@ .message-content { position: relative; max-width: var(--max-width); - &.gift { + &.gift, + &.auction { --max-width: 18rem; } diff --git a/src/components/middle/message/actions/StarGift.tsx b/src/components/middle/message/actions/StarGift.tsx index 31d04941f..0218e8e1b 100644 --- a/src/components/middle/message/actions/StarGift.tsx +++ b/src/components/middle/message/actions/StarGift.tsx @@ -72,23 +72,31 @@ const StarGiftAction = ({ const peer = isOutgoing ? recipient : sender; const isChannel = peer && isApiPeerChat(peer) && isChatChannel(peer); + const isAuction = action.isAuctionAcquired; const backgroundColor = useDynamicColorListener(ref, 'background-color', !action.gift.availabilityTotal); const fallbackPeerTitle = lang('ActionFallbackSomeone'); const peerTitle = peer && getPeerTitle(lang, peer); + const auctionToTitle = recipient && getPeerTitle(lang, recipient); const isSelf = sender?.id === recipient?.id; + const auctionBid = isAuction ? action.gift.stars : undefined; + const giftDescription = useMemo(() => { const peerLink = renderPeerLink(peer?.id, peerTitle || fallbackPeerTitle); const starsAmount = action.starsToConvert !== undefined ? formatStarsAsText(lang, action.starsToConvert) : undefined; + if (isAuction && auctionBid !== undefined) { + return lang('ActionStarGiftAuctionBought', { cost: formatStarsAsText(lang, auctionBid) }); + } + if (action.isUpgraded) { return lang('ActionStarGiftUpgraded'); } - if (action.alreadyPaidUpgradeStars) { + if (action.alreadyPaidUpgradeStars && !isAuction) { return translateWithYou( 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( lang, 'ActionStarGiftConvertText', !isOutgoing || isSelf, { peer: peerLink, amount: starsAmount }, ); @@ -116,8 +124,8 @@ const StarGiftAction = ({ lang, 'ActionStarGiftNoConvertText', !isOutgoing || isSelf, { peer: peerLink }, ); }, [ - action, fallbackPeerTitle, isChannel, isOutgoing, lang, message.date, peer?.id, peerTitle, starGiftMaxConvertPeriod, - isSelf, + action, auctionBid, fallbackPeerTitle, isAuction, isChannel, isOutgoing, lang, message.date, peer?.id, peerTitle, + starGiftMaxConvertPeriod, isSelf, ]); return ( @@ -157,7 +165,11 @@ const StarGiftAction = ({ )}

- {isSelf ? lang('ActionStarGiftSelf') : lang( + {isAuction && recipient ? lang( + 'ActionStarGiftAuctionFor', + { peer: renderPeerLink(recipient.id, auctionToTitle || fallbackPeerTitle) }, + { withNodes: true }, + ) : isSelf ? lang('ActionStarGiftSelf') : lang( isOutgoing ? 'ActionStarGiftTo' : 'ActionStarGiftFrom', { peer: renderPeerLink(peer?.id, peerTitle || fallbackPeerTitle), @@ -188,7 +200,8 @@ export default memo(withGlobal( const messageSender = selectSender(global, message); const giftSender = action.fromId ? selectPeer(global, action.fromId) : undefined; 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 { canPlayAnimatedEmojis, diff --git a/src/components/middle/message/helpers/buildContentClassName.ts b/src/components/middle/message/helpers/buildContentClassName.ts index 42b6d5bb5..4dc1cb746 100644 --- a/src/components/middle/message/helpers/buildContentClassName.ts +++ b/src/components/middle/message/helpers/buildContentClassName.ts @@ -144,6 +144,10 @@ export function buildContentClassName( if (webPage.gift) { classNames.push('gift'); } + + if (webPage.auction) { + classNames.push('auction'); + } } if (invoice && !invoice.extendedMedia) { diff --git a/src/components/middle/message/helpers/webpageType.ts b/src/components/middle/message/helpers/webpageType.ts index 31158219f..5e9da7cd0 100644 --- a/src/components/middle/message/helpers/webpageType.ts +++ b/src/components/middle/message/helpers/webpageType.ts @@ -1,7 +1,10 @@ +import type { IconName } from '../../../../types/icons'; 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 -export function getWebpageButtonLangKey(type?: string): RegularLangKey | undefined { +export function getWebpageButtonLangKey(type?: string, auctionEndDate?: number): RegularLangKey | undefined { switch (type) { case 'telegram_channel_request': case 'telegram_megagroup_request': @@ -37,7 +40,18 @@ export function getWebpageButtonLangKey(type?: string): RegularLangKey | undefin return 'ViewButtonEmojiset'; case 'telegram_nft': return 'ViewButtonGiftUnique'; + case 'telegram_auction': { + const isFinished = auctionEndDate !== undefined && auctionEndDate * 1000 < getServerTime(); + return isFinished ? 'PollViewResults' : 'GiftAuctionJoin'; + } default: return undefined; } } + +export function getWebpageButtonIcon(type?: string): IconName | undefined { + if (type === 'telegram_auction') { + return 'auction-filled'; + } + return undefined; +} diff --git a/src/components/modals/ModalContainer.tsx b/src/components/modals/ModalContainer.tsx index 227333fa6..87a079346 100644 --- a/src/components/modals/ModalContainer.tsx +++ b/src/components/modals/ModalContainer.tsx @@ -19,6 +19,11 @@ import CollectibleInfoModal from './collectible/CollectibleInfoModal.async'; import DeleteAccountModal from './deleteAccount/DeleteAccountModal.async'; import EmojiStatusAccessModal from './emojiStatusAccess/EmojiStatusAccessModal.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 GiftInfoModal from './gift/info/GiftInfoModal.async'; import GiftLockedModal from './gift/locked/GiftLockedModal.async'; @@ -94,6 +99,11 @@ type ModalKey = keyof Pick 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 ( +
+ {tableData.map(([label, value]) => ( + <> + {Boolean(label) &&
{label}
} +
+ {typeof value === 'object' && 'chatId' in value ? ( + + ) : value} +
+ + ))} +
+ ); +}; + +export default memo(TableInfo); diff --git a/src/components/modals/common/TableInfoModal.module.scss b/src/components/modals/common/TableInfoModal.module.scss index c539a85fc..399a6518e 100644 --- a/src/components/modals/common/TableInfoModal.module.scss +++ b/src/components/modals/common/TableInfoModal.module.scss @@ -1,5 +1,3 @@ -@use '../../../styles/mixins'; - .content { overflow-x: hidden; display: flex; @@ -10,55 +8,10 @@ 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 { 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 { align-self: center; } - -.chatItem { - width: fit-content; - color: var(--color-primary); - background-color: var(--color-background); -} diff --git a/src/components/modals/common/TableInfoModal.tsx b/src/components/modals/common/TableInfoModal.tsx index 999d342c5..d5cd41f2f 100644 --- a/src/components/modals/common/TableInfoModal.tsx +++ b/src/components/modals/common/TableInfoModal.tsx @@ -9,15 +9,13 @@ import buildClassName from '../../../util/buildClassName'; import useLastCallback from '../../../hooks/useLastCallback'; import Avatar from '../../common/Avatar'; -import PeerChip from '../../common/PeerChip'; import Button from '../../ui/Button'; import Modal from '../../ui/Modal'; +import TableInfo, { type TableData } from './TableInfo'; import styles from './TableInfoModal.module.scss'; -type ChatItem = { chatId: string; withEmojiStatus?: boolean }; - -export type TableData = [TeactNode | undefined, TeactNode | ChatItem][]; +export type { TableData }; type OwnProps = { isOpen?: boolean; @@ -59,7 +57,8 @@ const TableInfoModal = ({ currencyInBalanceBar, }: OwnProps) => { const { openChat } = getActions(); - const handleOpenChat = useLastCallback((peerId: string) => { + + const handleChatClick = useLastCallback((peerId: string) => { openChat({ id: peerId }); onClose(); }); @@ -84,25 +83,7 @@ const TableInfoModal = ({ )} {header} -
- {tableData?.map(([label, value]) => ( - <> - {Boolean(label) &&
{label}
} -
- {typeof value === 'object' && 'chatId' in value ? ( - - ) : value} -
- - ))} -
+ {footer} {buttonText && ( + {!hideBadge && ( + + )} {giftRibbon} {isLocked && }

diff --git a/src/components/modals/gift/GiftModal.module.scss b/src/components/modals/gift/GiftModal.module.scss index 04e19d692..121b7af9e 100644 --- a/src/components/modals/gift/GiftModal.module.scss +++ b/src/components/modals/gift/GiftModal.module.scss @@ -16,7 +16,7 @@ .root :global(.modal-dialog), .transition, .content { - height: min(92vh, 49rem); + height: min(98vh, 49rem); max-height: none !important; } diff --git a/src/components/modals/gift/GiftModal.tsx b/src/components/modals/gift/GiftModal.tsx index 53c83af3b..4db26b53c 100644 --- a/src/components/modals/gift/GiftModal.tsx +++ b/src/components/modals/gift/GiftModal.tsx @@ -41,7 +41,7 @@ import InfiniteScroll from '../../ui/InfiniteScroll'; import Modal from '../../ui/Modal'; import Transition from '../../ui/Transition'; import BalanceBlock from '../stars/BalanceBlock'; -import GiftSendingOptions from './GiftComposer'; +import GiftComposer from './GiftComposer'; import GiftItemPremium from './GiftItemPremium'; import GiftItemStar from './GiftItemStar'; import GiftModalResaleScreen from './GiftModalResaleScreen'; @@ -104,6 +104,8 @@ const GiftModal: FC = ({ closeResaleGiftsMarket, loadMyUniqueGifts, openGiftTransferConfirmModal, + setGiftModalSelectedGift, + clearActiveGiftAuction, } = getActions(); const dialogRef = useRef(); const transitionRef = useRef(); @@ -118,7 +120,7 @@ const GiftModal: FC = ({ const user = peer && isApiPeerUser(peer) ? peer : undefined; const chat = peer && isApiPeerChat(peer) ? peer : undefined; - const [selectedGift, setSelectedGift] = useState(); + const selectedGift = renderingModal?.selectedGift; const [shouldShowMainScreenHeader, setShouldShowMainScreenHeader] = useState(false); const [isMainScreenHeaderForStarGifts, setIsMainScreenHeaderForStarGifts] = useState(false); const [isGiftScreenHeaderForStarGifts, setIsGiftScreenHeaderForStarGifts] = useState(false); @@ -192,10 +194,14 @@ const GiftModal: FC = ({ useEffect(() => { if (!isOpen) { setShouldShowMainScreenHeader(false); - setSelectedGift(undefined); + setGiftModalSelectedGift({ gift: undefined }); setSelectedCategory('all'); } - }, [isOpen, tabId, closeResaleGiftsMarket]); + }, [isOpen]); + + useEffect(() => { + setIsGiftScreenHeaderForStarGifts(Boolean(selectedGift && 'id' in selectedGift)); + }, [selectedGift]); const handleScroll = useLastCallback((e: React.UIEvent) => { if (isGiftScreen) return; @@ -303,8 +309,7 @@ const GiftModal: FC = ({ openGiftInMarket({ gift, tabId }); return; } - setSelectedGift(gift); - setIsGiftScreenHeaderForStarGifts('id' in gift); + setGiftModalSelectedGift({ gift }); }); const handleMyGiftClick = useLastCallback((gift: ApiStarGift) => { @@ -423,7 +428,7 @@ const GiftModal: FC = ({ }); const handleCloseModal = useLastCallback(() => { - setSelectedGift(undefined); + setGiftModalSelectedGift({ gift: undefined }); resetResaleGifts(); closeGiftModal(); }); @@ -434,7 +439,8 @@ const GiftModal: FC = ({ return; } if (isGiftScreen) { - setSelectedGift(undefined); + setGiftModalSelectedGift({ gift: undefined }); + clearActiveGiftAuction(); return; } handleCloseModal(); @@ -589,7 +595,7 @@ const GiftModal: FC = ({ /> )} {isGiftScreen && renderingModal?.forPeerId && ( - { + const { modal } = props; + const GiftAuctionAcquiredModal = useModuleLoader(Bundles.Stars, 'GiftAuctionAcquiredModal', !modal); + + return GiftAuctionAcquiredModal ? : undefined; +}; + +export default GiftAuctionAcquiredModalAsync; diff --git a/src/components/modals/gift/auction/GiftAuctionAcquiredModal.module.scss b/src/components/modals/gift/auction/GiftAuctionAcquiredModal.module.scss new file mode 100644 index 000000000..02fe92d8b --- /dev/null +++ b/src/components/modals/gift/auction/GiftAuctionAcquiredModal.module.scss @@ -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; +} diff --git a/src/components/modals/gift/auction/GiftAuctionAcquiredModal.tsx b/src/components/modals/gift/auction/GiftAuctionAcquiredModal.tsx new file mode 100644 index 000000000..bacbfdead --- /dev/null +++ b/src/components/modals/gift/auction/GiftAuctionAcquiredModal.tsx @@ -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(); + + 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, ( + + {renderingGiftSticker && ( + + )} + {header} + + )], + [lang('GiftAuctionRecipient'), { chatId: gift.peerId }], + [lang('GiftAuctionDate'), formatDateTimeToString(gift.date * 1000, lang.code, true)], + [lang('GiftAuctionAcceptedBid'), ( + + {formatStarsAsIcon(lang, gift.bidAmount, { className: styles.starIcon })} + + {lang('GiftAuctionTopPosition', { position: gift.position })} + + + )], + ]; + + 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 ( + +
+
+ {giftItems?.map((item) => ( + + ))} +
+
+ +
+ ); +}; + +export default memo(withGlobal( + (global): Complete => { + const { giftAuctionAcquiredModal } = selectTabState(global); + + return { + acquiredGifts: giftAuctionAcquiredModal?.acquiredGifts, + giftTitle: giftAuctionAcquiredModal?.giftTitle, + giftSticker: giftAuctionAcquiredModal?.giftSticker, + }; + }, +)(GiftAuctionAcquiredModal)); diff --git a/src/components/modals/gift/auction/GiftAuctionBidModal.async.tsx b/src/components/modals/gift/auction/GiftAuctionBidModal.async.tsx new file mode 100644 index 000000000..935e73577 --- /dev/null +++ b/src/components/modals/gift/auction/GiftAuctionBidModal.async.tsx @@ -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 ? : undefined; +}; + +export default GiftAuctionBidModalAsync; diff --git a/src/components/modals/gift/auction/GiftAuctionBidModal.module.scss b/src/components/modals/gift/auction/GiftAuctionBidModal.module.scss new file mode 100644 index 000000000..7c6f53a12 --- /dev/null +++ b/src/components/modals/gift/auction/GiftAuctionBidModal.module.scss @@ -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; +} diff --git a/src/components/modals/gift/auction/GiftAuctionBidModal.tsx b/src/components/modals/gift/auction/GiftAuctionBidModal.tsx new file mode 100644 index 000000000..6dbb6f859 --- /dev/null +++ b/src/components/modals/gift/auction/GiftAuctionBidModal.tsx @@ -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 ( + <> + + + + + ); + }, [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) => { + 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 ( +
+
+
+ + {lang.number(currentMinBid)} +
+
{lang('GiftAuctionMinimumBid')}
+
+
+
+ +
+
{lang('GiftAuctionUntilNextRound')}
+
+
+
+ + {lang.number(activeState?.giftsLeft || 0)} +
+
{lang('GiftAuctionLeft')}
+
+
+ ); + } + + 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 ( + + {isWinning ? ( +
+ {lang('GiftAuctionYoureWinning')} + + {lang('GiftUnique', { title: giftTitle, number: nextGiftNum ? lang.number(nextGiftNum) : undefined })} + +
+ ) : ( +
{lang('GiftAuctionYourBidWillBe')}
+ )} +
+ ); + } + + function renderUserBid() { + return ( +
+ {renderCurrentBidSectionTitle()} +
+
+ {userPosition && userPosition > 100 ? `${userPosition}+` : (userPosition || 1)} +
+
+ {currentUserPeer && } + {currentUserPeer && } +
+
+ + {lang.number(selectedBidAmount)} +
+
+
+ ); + } + + function renderTopBidderRow( + index: number, + emoji: string, + peer: ApiPeer | undefined, + amount: number | undefined, + activeKey: number, + ) { + return ( +
+
+ {renderText(emoji, ['emoji'])} +
+ + {peer && ( + <> + + + + )} + + {amount !== undefined && ( +
+ + {lang.number(amount)} +
+ )} +
+ ); + } + + function renderTopWinners() { + const topCount = DEFAULT_TOP_BIDDERS_COUNT; + const bidLevels = activeState?.bidLevels; + + return ( +
+
+ {lang('GiftAuctionTopWinners', { count: topCount }, { pluralValue: topCount })} +
+ {renderTopBidderRow(0, '🥇', topBidder1, bidLevels?.[0]?.amount, topBidder1Key)} + {renderTopBidderRow(1, '🥈', topBidder2, bidLevels?.[1]?.amount, topBidder2Key)} + {renderTopBidderRow(2, '🥉', topBidder3, bidLevels?.[2]?.amount, topBidder3Key)} +
+ ); + } + + return ( + +
+ +
+ + + +

{lang('GiftAuctionPlaceBid')}

+ {renderInfoCards()} + + {renderUserBid()} + {renderTopWinners()} + + + +

{lang('GiftAuctionCustomBidDescription', { count: renderingAuctionState?.gift.giftsPerRound })}

+
+ + +
+
+
+ ); +}; + +export default memo(withGlobal( + (global): Complete => { + 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)); diff --git a/src/components/modals/gift/auction/GiftAuctionChangeRecipientModal.async.tsx b/src/components/modals/gift/auction/GiftAuctionChangeRecipientModal.async.tsx new file mode 100644 index 000000000..c9105a742 --- /dev/null +++ b/src/components/modals/gift/auction/GiftAuctionChangeRecipientModal.async.tsx @@ -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 ? : undefined; +}; + +export default GiftAuctionChangeRecipientModalAsync; diff --git a/src/components/modals/gift/auction/GiftAuctionChangeRecipientModal.module.scss b/src/components/modals/gift/auction/GiftAuctionChangeRecipientModal.module.scss new file mode 100644 index 000000000..63ae1f0c4 --- /dev/null +++ b/src/components/modals/gift/auction/GiftAuctionChangeRecipientModal.module.scss @@ -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); +} diff --git a/src/components/modals/gift/auction/GiftAuctionChangeRecipientModal.tsx b/src/components/modals/gift/auction/GiftAuctionChangeRecipientModal.tsx new file mode 100644 index 000000000..b88572921 --- /dev/null +++ b/src/components/modals/gift/auction/GiftAuctionChangeRecipientModal.tsx @@ -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 ( + +
+ + + +
+

+ {lang('GiftAuctionChangeRecipientDescription', { + oldPeer: getPeerTitle(lang, renderingOldPeer), + newPeer: getPeerTitle(lang, renderingNewPeer), + }, { + withNodes: true, + withMarkdown: true, + })} +

+
+ ); +}; + +export default memo( + withGlobal((global, { modal }): Complete => { + const oldPeer = modal?.oldPeerId ? selectPeer(global, modal.oldPeerId) : undefined; + const newPeer = modal?.newPeerId ? selectPeer(global, modal.newPeerId) : undefined; + + return { + oldPeer, + newPeer, + }; + })(GiftAuctionChangeRecipientModal), +); diff --git a/src/components/modals/gift/auction/GiftAuctionInfoModal.async.tsx b/src/components/modals/gift/auction/GiftAuctionInfoModal.async.tsx new file mode 100644 index 000000000..0ea0d7697 --- /dev/null +++ b/src/components/modals/gift/auction/GiftAuctionInfoModal.async.tsx @@ -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 ? : undefined; +}; + +export default GiftAuctionInfoModalAsync; diff --git a/src/components/modals/gift/auction/GiftAuctionInfoModal.module.scss b/src/components/modals/gift/auction/GiftAuctionInfoModal.module.scss new file mode 100644 index 000000000..427d5276b --- /dev/null +++ b/src/components/modals/gift/auction/GiftAuctionInfoModal.module.scss @@ -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; +} diff --git a/src/components/modals/gift/auction/GiftAuctionInfoModal.tsx b/src/components/modals/gift/auction/GiftAuctionInfoModal.tsx new file mode 100644 index 000000000..12aaefca9 --- /dev/null +++ b/src/components/modals/gift/auction/GiftAuctionInfoModal.tsx @@ -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 ( +
+
+ +
+
+ {lang('GiftAuctionInfoTitle')} +
+
+ {lang('GiftAuctionInfoSubtitle')} +
+
+ ); + }, [lang]); + + const footer = useMemo(() => { + if (!isOpen) return undefined; + return ( +
+ +
+ ); + }, [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 ( + + ); +}; + +export default memo(withGlobal( + (global): Complete => { + const { activeGiftAuction } = selectTabState(global); + + return { + activeGiftAuction, + }; + }, +)(GiftAuctionInfoModal)); diff --git a/src/components/modals/gift/auction/GiftAuctionModal.async.tsx b/src/components/modals/gift/auction/GiftAuctionModal.async.tsx new file mode 100644 index 000000000..3bfd37a10 --- /dev/null +++ b/src/components/modals/gift/auction/GiftAuctionModal.async.tsx @@ -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 ? : undefined; +}; + +export default GiftAuctionModalAsync; diff --git a/src/components/modals/gift/auction/GiftAuctionModal.module.scss b/src/components/modals/gift/auction/GiftAuctionModal.module.scss new file mode 100644 index 000000000..aa2d0a91d --- /dev/null +++ b/src/components/modals/gift/auction/GiftAuctionModal.module.scss @@ -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; +} diff --git a/src/components/modals/gift/auction/GiftAuctionModal.tsx b/src/components/modals/gift/auction/GiftAuctionModal.tsx new file mode 100644 index 000000000..77ee32105 --- /dev/null +++ b/src/components/modals/gift/auction/GiftAuctionModal.tsx @@ -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 ( +
+ +

+ {giftTitle} +

+ {isFinished ? ( + {lang('GiftAuctionEnded')} + ) : ( +

+ {lang('GiftAuctionTopBidders', { + count: giftsPerRound, + gift: {giftTitle}, + link: {lang('GiftAuctionLearnMore')}, + }, { pluralValue: giftsPerRound, withNodes: true, withMarkdown: true })} +

+ )} +
+ ); + }, [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 = ( +
+ {acquiredCount > 0 && ( + + {lang('GiftAuctionItemsBought', { + count: acquiredCount, + gift: giftSticker && ( + + ), + }, { pluralValue: acquiredCount, withNodes: true })} + + )} + +
+ ); + + return { + tableData, + footer, + }; + }, [gift, state, userState, isFinished, lang, handleJoinClick, handleItemsBoughtClick, handleClose]); + + return ( + + ); +}; + +export default memo(withGlobal( + (global): Complete => { + const { activeGiftAuction } = selectTabState(global); + + return { + auctionState: activeGiftAuction, + }; + }, +)(GiftAuctionModal)); diff --git a/src/components/modals/gift/info/GiftInfoModal.module.scss b/src/components/modals/gift/info/GiftInfoModal.module.scss index 86ed1a108..28efeb65a 100644 --- a/src/components/modals/gift/info/GiftInfoModal.module.scss +++ b/src/components/modals/gift/info/GiftInfoModal.module.scss @@ -42,8 +42,8 @@ margin-bottom: 0; } -.soldOut { - color: var(--color-error); +.warningDescription { + color: var(--color-error) !important; } .modalContent { @@ -51,18 +51,6 @@ 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 { position: absolute; z-index: 1; diff --git a/src/components/modals/gift/info/GiftInfoModal.tsx b/src/components/modals/gift/info/GiftInfoModal.tsx index 019cca15a..96d1512de 100644 --- a/src/components/modals/gift/info/GiftInfoModal.tsx +++ b/src/components/modals/gift/info/GiftInfoModal.tsx @@ -440,9 +440,12 @@ const GiftInfoModal = ({ const isVisibleForMe = isNameHidden && renderingTargetPeer; + const isWarningDescription = savedGift?.isRefunded || (!savedGift && gift?.type === 'starGift'); + const description = (() => { if (!savedGift) return lang('GiftInfoSoldOutDescription'); if (isTargetChat) return undefined; + if (savedGift.isRefunded) return lang('GiftInfoDescriptionRefunded'); if (savedGift.upgradeMsgId) return lang('GiftInfoDescriptionUpgraded'); if (canManage && savedGift.canUpgrade && savedGift.alreadyPaidUpgradeStars && !savedGift.upgradeMsgId) { @@ -592,7 +595,7 @@ const GiftInfoModal = ({ {getTitle()} {Boolean(description) && ( -

+

{description}

)} diff --git a/src/components/modals/gift/upgrade/GiftUpgradeModal.tsx b/src/components/modals/gift/upgrade/GiftUpgradeModal.tsx index fbf886b74..20438cfe3 100644 --- a/src/components/modals/gift/upgrade/GiftUpgradeModal.tsx +++ b/src/components/modals/gift/upgrade/GiftUpgradeModal.tsx @@ -5,10 +5,7 @@ import { getActions, withGlobal } from '../../../../global'; import type { ApiPeer, - ApiStarGiftAttribute, - ApiStarGiftAttributeBackdrop, ApiStarGiftAttributeModel, - ApiStarGiftAttributePattern, } from '../../../../api/types'; import type { TabState } from '../../../../global/types'; import { ApiMediaFormat } from '../../../../api/types'; @@ -17,6 +14,7 @@ import { getStickerMediaHash } from '../../../../global/helpers'; import { getPeerTitle } from '../../../../global/helpers/peers'; import { selectPeer } from '../../../../global/selectors'; import { fetch } from '../../../../util/mediaLoader'; +import { getRandomGiftPreviewAttributes, type GiftPreviewAttributes } from '../../../common/helpers/gifts'; import useInterval from '../../../../hooks/schedulers/useInterval'; import useCurrentOrPrev from '../../../../hooks/useCurrentOrPrev'; @@ -42,12 +40,6 @@ type StateProps = { recipient?: ApiPeer; }; -type Attributes = { - model: ApiStarGiftAttributeModel; - pattern: ApiStarGiftAttributePattern; - backdrop: ApiStarGiftAttributeBackdrop; -}; - const PREVIEW_UPDATE_INTERVAL = 3000; const GiftUpgradeModal = ({ modal, recipient }: OwnProps & StateProps) => { @@ -67,7 +59,7 @@ const GiftUpgradeModal = ({ modal, recipient }: OwnProps & StateProps) => { const isPrepaid = Boolean(renderingModal?.gift?.prepaidUpgradeHash); - const [previewAttributes, setPreviewAttributes] = useState(); + const [previewAttributes, setPreviewAttributes] = useState(); const lang = useLang(); @@ -111,7 +103,7 @@ const GiftUpgradeModal = ({ modal, recipient }: OwnProps & StateProps) => { const updatePreviewAttributes = useLastCallback(() => { if (!renderingModal?.sampleAttributes) return; - setPreviewAttributes(getRandomAttributes(renderingModal.sampleAttributes, previewAttributes)); + setPreviewAttributes(getRandomGiftPreviewAttributes(renderingModal.sampleAttributes, previewAttributes)); }); const handleOpenPriceInfo = useLastCallback(() => { @@ -274,25 +266,3 @@ export default memo(withGlobal( }; }, )(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, - }; -} diff --git a/src/components/modals/paidReaction/StarSlider.module.scss b/src/components/modals/paidReaction/StarSlider.module.scss index c875171f1..def7b6b60 100644 --- a/src/components/modals/paidReaction/StarSlider.module.scss +++ b/src/components/modals/paidReaction/StarSlider.module.scss @@ -1,7 +1,10 @@ @use "../../../styles/mixins"; +/* stylelint-disable plugin/no-low-performance-animation-properties */ + .root { --_size: 1.875rem; + --_transition: 0.15s; --progress: 0; position: relative; @@ -9,6 +12,24 @@ padding-top: 4rem; @include mixins.reset-range(); + + &.dragging { + .progress { + transition: background-color var(--_transition); + } + + .floatingBadgeWrapper { + transition: none; + } + + .floatingBadgeText { + transition: background-color var(--_transition); + } + + .floatingBadgeTriangle { + transition: none; + } + } } .slider { @@ -79,6 +100,8 @@ background-image: var(--stars-gradient); + transition: width var(--_transition), background-color var(--_transition); + &::after { content: ""; @@ -93,12 +116,14 @@ background-color: white; } + + &.dynamicColor { + background-color: var(--dynamic-color); + background-image: none; + } } .floatingBadgeWrapper { - --_min-x: 0; - --_max-x: 100%; - pointer-events: none; position: absolute; @@ -107,11 +132,13 @@ transform: translateX( clamp( - var(--_min-x), + var(--min-badge-x, 0px), calc(var(--_size) / 2 + var(--progress) * (100% - var(--_size))), - var(--_max-x), + var(--max-badge-x, 100%) ) ); + + transition: transform var(--_transition); } .floatingBadge { @@ -121,12 +148,15 @@ top: -1rem; left: 0; transform: translate(-50%, -100%); + + &.clickable { + pointer-events: auto; + cursor: pointer; + } } .floatingBadgeText { - display: flex; - gap: 0.125rem; - align-items: center; + position: relative; padding: 0.5rem 1rem; border-radius: 2rem; @@ -138,6 +168,65 @@ white-space: nowrap; 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 { @@ -145,5 +234,22 @@ z-index: -1; bottom: 0; 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); } diff --git a/src/components/modals/paidReaction/StarSlider.tsx b/src/components/modals/paidReaction/StarSlider.tsx index 08e618acc..2a9034ea5 100644 --- a/src/components/modals/paidReaction/StarSlider.tsx +++ b/src/components/modals/paidReaction/StarSlider.tsx @@ -1,14 +1,15 @@ -import type React from '../../../lib/teact/teact'; +import type { TeactNode } from '../../../lib/teact/teact'; import { - memo, useMemo, useRef, useState, -} from '../../../lib/teact/teact'; + memo, useEffect, + useMemo, useRef, useState } from '../../../lib/teact/teact'; -import { requestMeasure, requestMutation } from '../../../lib/fasterdom/fasterdom'; 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 usePrevious from '../../../hooks/usePrevious'; import useResizeObserver from '../../../hooks/useResizeObserver'; import AnimatedCounter from '../../common/AnimatedCounter'; @@ -20,87 +21,264 @@ import styles from './StarSlider.module.scss'; type OwnProps = { maxValue: number; defaultValue: number; + minValue?: number; + minAllowedValue?: number; className?: string; + floatingBadgeDescription?: TeactNode; + shouldUseDynamicColor?: boolean; + shouldAllowCustomValue?: boolean; onChange: (value: number) => void; + onBadgeClick?: NoneToVoidFunction; }; 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 = ({ maxValue, defaultValue, + minValue, + minAllowedValue, className, + floatingBadgeDescription, + shouldUseDynamicColor, + shouldAllowCustomValue, onChange, + onBadgeClick, }: OwnProps) => { - const floatingBadgeRef = useRef(); + const containerRef = useRef(); + const floatingBadgeContentRef = useRef(); + const lang = useLang(); + + const min = minValue ?? 1; const points = useMemo(() => { const result = []; + for (let i = 0; i < DEFAULT_POINTS.length; i++) { + if (DEFAULT_POINTS[i] <= min) continue; + if (DEFAULT_POINTS[i] < maxValue) { result.push(DEFAULT_POINTS[i]); } if (DEFAULT_POINTS[i] >= 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; - }, [maxValue]); + }, [maxValue, min]); const [value, setValue] = useState(0); + const [containerWidth, setContainerWidth] = useState(0); + const [badgeWidth, setBadgeWidth] = useState(0); + const [isDragging, setIsDragging] = useState(false); + const startXRef = useRef(); + const prevBadgeWidth = usePrevious(badgeWidth); - useEffectOnce(() => { - setValue(getProgress(points, defaultValue)); - }); + const badgeText = lang.number(getValue(points, value, min)); - const updateSafeBadgePosition = useLastCallback(() => { - const badge = floatingBadgeRef.current; - if (!badge) return; - const parent = badge.parentElement!; + const minAllowedProgress = minAllowedValue !== undefined + ? getProgress(points, minAllowedValue, min) : 0; - requestMeasure(() => { - const safeMinX = parent.offsetLeft + badge.offsetWidth / 2; - const safeMaxX = parent.offsetLeft + parent.offsetWidth - badge.offsetWidth / 2; + useEffect(() => { + setValue(getProgress(points, defaultValue, min)); + }, [defaultValue, points, min]); - requestMutation(() => { - parent.style.setProperty('--_min-x', `${safeMinX}px`); - parent.style.setProperty('--_max-x', `${safeMaxX}px`); - }); + useEffect(() => { + if (!floatingBadgeContentRef.current) return; + + 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) => { - const newValue = Number(event.currentTarget.value); - setValue(newValue); + const rawValue = Number(event.currentTarget.value); + 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) => { + startXRef.current = e.clientX; + setIsDragging(false); + }); + + const handlePointerMove = useLastCallback((e: React.PointerEvent) => { + 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 ( -
+
-
-
- - +
+
+ +
+
+ + +
+
+ {floatingBadgeDescription} +
+
- - - - - - - - +
-
+
+ {shouldAllowCustomValue && ( + + )}
); }; -function getProgress(points: number[], value: number) { +function getProgress(points: number[], value: number, minValue: number) { 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]; + if (nextPoint === prevPoint) return pointIndex; const progress = (value - prevPoint) / (nextPoint - prevPoint); return pointIndex + progress; } -function getValue(points: number[], progress: number) { +function getValue(points: number[], progress: number, minValue: number) { 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 value = prevPoint + (nextPoint - prevPoint) * (progress - pointIndex); 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); diff --git a/src/components/modals/stars/helpers/transaction.ts b/src/components/modals/stars/helpers/transaction.ts index 7cb84b050..c00bbfb8d 100644 --- a/src/components/modals/stars/helpers/transaction.ts +++ b/src/components/modals/stars/helpers/transaction.ts @@ -37,6 +37,12 @@ export function getTransactionTitle(oldLang: OldLangFn, lang: LangFn, transactio return lang('GiftPrepaidUpgradeTransactionTitle'); } + if (transaction.isStarGiftAuctionBid) { + return isNegativeAmount(transaction.amount) + ? lang('StarGiftAuctionBidTransaction') + : lang('StarGiftAuctionBidRefundedTransaction'); + } + if (transaction.starRefCommision) { return oldLang('StarTransactionCommission', formatPercent(transaction.starRefCommision)); } diff --git a/src/components/modals/stars/transaction/StarsTransactionModal.tsx b/src/components/modals/stars/transaction/StarsTransactionModal.tsx index a74b1b556..ce9aac09b 100644 --- a/src/components/modals/stars/transaction/StarsTransactionModal.tsx +++ b/src/components/modals/stars/transaction/StarsTransactionModal.tsx @@ -260,7 +260,7 @@ const StarsTransactionModal: FC = ({ peerLabel = oldLang('Stars.Transaction.Via'); } - if (!transaction.isPostsSearch && !isDropOriginalDetails) { + if (!transaction.isPostsSearch && !isDropOriginalDetails && !transaction.isStarGiftAuctionBid) { tableData.push([ peerLabel, peerId ? { chatId: peerId } : toName || '', @@ -312,6 +312,18 @@ const StarsTransactionModal: FC = ({ 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 footerTextParts = footerText.split('{link}'); diff --git a/src/components/ui/TextTimer.tsx b/src/components/ui/TextTimer.tsx index 6aee9ed87..2941d7080 100644 --- a/src/components/ui/TextTimer.tsx +++ b/src/components/ui/TextTimer.tsx @@ -10,12 +10,13 @@ import AnimatedCounter from '../common/AnimatedCounter'; type OwnProps = { endsAt: number; + shouldShowZeroOnEnd?: boolean; onEnd?: NoneToVoidFunction; }; 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 serverTime = getServerTime(); @@ -28,9 +29,9 @@ const TextTimer = ({ endsAt, onEnd }: OwnProps) => { } }, [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 timeParts = time.split(':'); diff --git a/src/global/actions/api/payments.ts b/src/global/actions/api/payments.ts index 6e874e398..dca1b3984 100644 --- a/src/global/actions/api/payments.ts +++ b/src/global/actions/api/payments.ts @@ -1,5 +1,6 @@ import type { - ApiInputInvoice, ApiInputInvoicePremiumGiftStars, ApiInputInvoiceStarGift, ApiInputInvoiceStarGiftResale, + ApiInputInvoice, ApiInputInvoicePremiumGiftStars, ApiInputInvoiceStarGift, + ApiInputInvoiceStarGiftAuctionBid, ApiInputInvoiceStarGiftResale, ApiRequestInputInvoice, } from '../../../api/types'; import type { ApiCredentials } from '../../../components/payment/PaymentModal'; @@ -575,7 +576,7 @@ addActionHandler('checkCanSendGift', async (global, actions, payload): Promise => { const { - forUserId, selectedResaleGift, tabId = getCurrentTabId(), + forUserId, selectedGift, selectedResaleGift, tabId = getCurrentTabId(), } = payload; if (selectIsCurrentUserFrozen(global)) { @@ -592,6 +593,7 @@ addActionHandler('openGiftModal', async (global, actions, payload): Promise { + 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( global: T, inputInvoice: ApiInputInvoice, price: number, ...[tabId = getCurrentTabId()]: TabArgs @@ -1229,6 +1249,26 @@ addActionHandler('openUniqueGiftBySlug', async (global, actions, payload): Promi actions.openGiftInfoModal({ gift, tabId }); }); +addActionHandler('openGiftAuctionBySlug', async (global, actions, payload): Promise => { + 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 => { const { gift, password, tabId = getCurrentTabId(), diff --git a/src/global/actions/api/stars.ts b/src/global/actions/api/stars.ts index ab4bfd283..9e9d08d31 100644 --- a/src/global/actions/api/stars.ts +++ b/src/global/actions/api/stars.ts @@ -12,11 +12,12 @@ import { getServerTime } from '../../../util/serverTime'; import { callApi } from '../../../api/gramjs'; import { RESALE_GIFTS_LIMIT } from '../../../limits'; import { areInputSavedGiftsEqual, getRequestInputSavedStarGift } from '../../helpers/payments'; -import { addActionHandler, getGlobal, setGlobal } from '../../index'; +import { addActionHandler, getGlobal, getPromiseActions, setGlobal } from '../../index'; import { appendStarsSubscriptions, appendStarsTransactions, replacePeerSavedGifts, + updateActiveGiftAuction, updateChats, updatePeerStarGiftCollections, updateStarsBalance, @@ -579,6 +580,43 @@ addActionHandler('shiftGiftUpgradeNextPrice', async (global, _actions, payload): setGlobal(global); }); +addActionHandler('openGiftAuctionModal', async (global, _actions, payload): Promise => { + 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 => { + 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 => { const { gift, peerId, tabId = getCurrentTabId() } = payload; @@ -650,3 +688,26 @@ addActionHandler('loadStarGiftCollections', async (global, actions, payload): Pr global = updatePeerStarGiftCollections(global, peerId, result.collections); setGlobal(global); }); + +addActionHandler('openGiftAuctionAcquiredModal', async (global, actions, payload): Promise => { + 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); +}); diff --git a/src/global/actions/apiUpdaters/misc.ts b/src/global/actions/apiUpdaters/misc.ts index 399c8f476..8bdc25bb3 100644 --- a/src/global/actions/apiUpdaters/misc.ts +++ b/src/global/actions/apiUpdaters/misc.ts @@ -240,6 +240,40 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => { case 'newMessage': { 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 (action?.type !== 'starGiftUnique') return undefined; const actionStarGift = action.gift; diff --git a/src/global/actions/apiUpdaters/payments.ts b/src/global/actions/apiUpdaters/payments.ts index 3a2565581..3fd068987 100644 --- a/src/global/actions/apiUpdaters/payments.ts +++ b/src/global/actions/apiUpdaters/payments.ts @@ -4,7 +4,12 @@ import { formatCurrencyAsString } from '../../../util/formatCurrency'; import * as langProvider from '../../../util/oldLangProvider'; import { getPeerTitle } from '../../helpers/peers'; import { addActionHandler, getGlobal, setGlobal } from '../../index'; -import { removeGiftInfoOriginalDetails, updateStarsBalance } from '../../reducers'; +import { + removeGiftInfoOriginalDetails, + updateActiveGiftAuctionState, + updateActiveGiftAuctionUserState, + updateStarsBalance, +} from '../../reducers'; import { updateTabState } from '../../reducers/tabs'; 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; } @@ -221,5 +247,29 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => { actions.loadStarStatus(); 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; + } } }); diff --git a/src/global/actions/ui/stars.ts b/src/global/actions/ui/stars.ts index b176d3a29..57839f902 100644 --- a/src/global/actions/ui/stars.ts +++ b/src/global/actions/ui/stars.ts @@ -11,8 +11,7 @@ import { callApi } from '../../../api/gramjs'; import { addTabStateResetterAction } from '../../helpers/meta'; import { getPrizeStarsTransactionFromGiveaway, getStarsTransactionFromGift } from '../../helpers/payments'; import { addActionHandler, getGlobal, setGlobal } from '../../index'; -import { - clearStarPayment, openStarsTransactionModal, +import { clearStarPayment, openStarsTransactionModal, } from '../../reducers'; import { updateTabState } from '../../reducers/tabs'; import { @@ -206,6 +205,31 @@ addTabStateResetterAction('closeStarsSubscriptionModal', 'starsSubscriptionModal 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 => { const { tabId = getCurrentTabId() } = payload || {}; return updateTabState(global, { @@ -387,6 +411,52 @@ addTabStateResetterAction('closeGiftResalePriceComposerModal', 'giftResalePriceC 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 => { const { prices, currentPrice, minPrice, maxPrice, tabId = getCurrentTabId(), diff --git a/src/global/helpers/payments.ts b/src/global/helpers/payments.ts index 13b2f2289..dac43c3f7 100644 --- a/src/global/helpers/payments.ts +++ b/src/global/helpers/payments.ts @@ -261,6 +261,23 @@ export function getRequestInputInvoice( }; } + 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; } diff --git a/src/global/reducers/gifts.ts b/src/global/reducers/gifts.ts index 928160efe..59251e80e 100644 --- a/src/global/reducers/gifts.ts +++ b/src/global/reducers/gifts.ts @@ -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 { getCurrentTabId } from '../../util/establishMultitabRole'; +import { selectTabState } from '../selectors'; import { updateTabState } from './tabs'; export function removeGiftInfoOriginalDetails( @@ -46,3 +52,73 @@ export function removeGiftInfoOriginalDetails( }, }, tabId); } + +function getAuctionStateVersion(state: ApiTypeStarGiftAuctionState): number { + return state.type === 'active' ? state.version : 0; +} + +export function updateActiveGiftAuction( + 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( + 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( + 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); +} diff --git a/src/global/types/actions.ts b/src/global/types/actions.ts index ce1b6543f..550e4ee1d 100644 --- a/src/global/types/actions.ts +++ b/src/global/types/actions.ts @@ -33,6 +33,7 @@ import type { ApiPaymentStatus, ApiPeer, ApiPhoto, + ApiPremiumGiftCodeOption, ApiPremiumSection, ApiPreparedInlineMessage, ApiPrivacyKey, @@ -46,6 +47,7 @@ import type { ApiSessionData, ApiStarGift, ApiStarGiftAttributeOriginalDetails, + ApiStarGiftRegular, ApiStarGiftUnique, ApiStarGiftUpgradePrice, ApiStarsSubscription, @@ -1653,6 +1655,9 @@ export interface ActionPayloads { openUniqueGiftBySlug: { slug: string; } & WithTabId; + openGiftAuctionBySlug: { + slug: string; + } & WithTabId; openPreviousStory: WithTabId | undefined; openNextStory: WithTabId | undefined; setStoryViewerMuted: { @@ -2600,9 +2605,13 @@ export interface ActionPayloads { openGiftModal: { forUserId: string; + selectedGift?: ApiStarGift; selectedResaleGift?: ApiStarGift; } & WithTabId; closeGiftModal: WithTabId | undefined; + setGiftModalSelectedGift: { + gift: ApiPremiumGiftCodeOption | ApiStarGift | undefined; + } & WithTabId; sendStarGift: StarGiftInfo & WithTabId; buyStarGift: { peerId: string; @@ -2686,6 +2695,45 @@ export interface ActionPayloads { gift: ApiStarGiftUnique; } & WithTabId; 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: { gift: ApiInputSavedStarGift; password: string; diff --git a/src/global/types/tabState.ts b/src/global/types/tabState.ts index e6ccf51e2..007ee303c 100644 --- a/src/global/types/tabState.ts +++ b/src/global/types/tabState.ts @@ -44,6 +44,8 @@ import type { ApiStarGiftAttribute, ApiStarGiftAttributeCounter, ApiStarGiftAttributeOriginalDetails, + ApiStarGiftAuctionAcquiredGift, + ApiStarGiftAuctionState, ApiStarGiftUnique, ApiStarGiftUpgradePrice, ApiStarGiveawayOption, @@ -703,7 +705,9 @@ export type TabState = { forPeerId: string; gifts?: ApiPremiumGiftCodeOption[]; selectedResaleGift?: ApiStarGift; + selectedGift?: ApiPremiumGiftCodeOption | ApiStarGift; }; + activeGiftAuction?: ApiStarGiftAuctionState; chatRefundModal?: { userId: string; starsToRefund: number; @@ -889,6 +893,36 @@ export type TabState = { 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?: { prices: ApiStarGiftUpgradePrice[]; currentPrice: number; diff --git a/src/hooks/useScrollNotch.ts b/src/hooks/useScrollNotch.ts index bd71db1de..183782d56 100644 --- a/src/hooks/useScrollNotch.ts +++ b/src/hooks/useScrollNotch.ts @@ -12,10 +12,12 @@ const useScrollNotch = ({ containerRef, selector, isBottomNotch, + shouldHideTopNotch, }: { containerRef: ElementRef; selector: string; isBottomNotch?: boolean; + shouldHideTopNotch?: boolean; }, deps: unknown[]) => { useLayoutEffect(() => { const elements = containerRef.current?.querySelectorAll(selector); @@ -28,19 +30,21 @@ const useScrollNotch = ({ const isAtEnd = scrollHeight - scrollTop - clientHeight < SCROLL_THRESHOLD; requestMutation(() => { + if (!shouldHideTopNotch) { + toggleExtraClass(target, 'scrolled', isScrolled); + } if (isBottomNotch) { toggleExtraClass(target, 'scrolled-to-end', isAtEnd); - } else { - toggleExtraClass(target, 'scrolled', isScrolled); } }); }, THROTTLE_DELAY); elements.forEach((el) => { + if (!shouldHideTopNotch) { + addExtraClass(el, 'with-notch'); + } if (isBottomNotch) { addExtraClass(el, 'with-bottom-notch'); - } else { - addExtraClass(el, 'with-notch'); } el.addEventListener('scroll', handleScroll, { passive: true }); }); @@ -55,7 +59,7 @@ const useScrollNotch = ({ }); }; // eslint-disable-next-line react-hooks-static-deps/exhaustive-deps - }, [containerRef, selector, isBottomNotch, ...deps]); + }, [containerRef, selector, isBottomNotch, shouldHideTopNotch, ...deps]); useEffect(() => { const elements = containerRef.current?.querySelectorAll(selector); @@ -67,15 +71,16 @@ const useScrollNotch = ({ const isAtEnd = scrollHeight - scrollTop - clientHeight < SCROLL_THRESHOLD; requestMutation(() => { + if (!shouldHideTopNotch) { + toggleExtraClass(el, 'scrolled', isScrolled); + } if (isBottomNotch) { toggleExtraClass(el, 'scrolled-to-end', isAtEnd); - } else { - toggleExtraClass(el, 'scrolled', isScrolled); } }); }); // eslint-disable-next-line react-hooks-static-deps/exhaustive-deps - }, [containerRef, selector, isBottomNotch, ...deps]); + }, [containerRef, selector, isBottomNotch, shouldHideTopNotch, ...deps]); }; export default useScrollNotch; diff --git a/src/lib/gramjs/tl/apiTl.ts b/src/lib/gramjs/tl/apiTl.ts index 0cbbfdb8c..8e8fadab7 100644 --- a/src/lib/gramjs/tl/apiTl.ts +++ b/src/lib/gramjs/tl/apiTl.ts @@ -1881,6 +1881,8 @@ payments.updateStarGiftPrice#edbe6ccb stargift:InputSavedStarGift resell_amount: payments.getStarGiftCollections#981b91dd peer:InputPeer hash:long = payments.StarGiftCollections; payments.getUniqueStarGiftValueInfo#4365af6b slug:string = payments.UniqueStarGiftValueInfo; 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.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; diff --git a/src/lib/gramjs/tl/static/api.json b/src/lib/gramjs/tl/static/api.json index 04593281e..e56105753 100644 --- a/src/lib/gramjs/tl/static/api.json +++ b/src/lib/gramjs/tl/static/api.json @@ -352,6 +352,8 @@ "payments.getResaleStarGifts", "payments.updateStarGiftPrice", "payments.getStarGiftCollections", + "payments.getStarGiftAuctionState", + "payments.getStarGiftAuctionAcquiredGifts", "langpack.getLangPack", "langpack.getStrings", "langpack.getLanguages", diff --git a/src/styles/icons.css b/src/styles/icons.css index 5c280a21d..ba26a5b5b 100644 --- a/src/styles/icons.css +++ b/src/styles/icons.css @@ -3,8 +3,8 @@ font-weight: normal; font-style: normal; font-display: block; - src: url("./icons.woff2?a07bab7d97a4c6540cca18b1d787228b") format("woff2"), -url("./icons.woff?a07bab7d97a4c6540cca18b1d787228b") format("woff"); + src: url("./icons.woff2?78af88c0f83feccd1a41bd4d851b003d") format("woff2"), +url("./icons.woff?78af88c0f83feccd1a41bd4d851b003d") format("woff"); } .icon-char::before { @@ -78,867 +78,876 @@ url("./icons.woff?a07bab7d97a4c6540cca18b1d787228b") format("woff"); .icon-attach::before { content: "\f113"; } -.icon-auction::before { +.icon-auction-drop::before { content: "\f114"; } -.icon-author-hidden::before { +.icon-auction-filled::before { content: "\f115"; } -.icon-avatar-archived-chats::before { +.icon-auction-next-round::before { content: "\f116"; } -.icon-avatar-deleted-account::before { +.icon-auction::before { content: "\f117"; } -.icon-avatar-saved-messages::before { +.icon-author-hidden::before { content: "\f118"; } -.icon-bold::before { +.icon-avatar-archived-chats::before { content: "\f119"; } -.icon-boost-outline::before { +.icon-avatar-deleted-account::before { content: "\f11a"; } -.icon-boost::before { +.icon-avatar-saved-messages::before { content: "\f11b"; } -.icon-boostcircle::before { +.icon-bold::before { content: "\f11c"; } -.icon-boosts::before { +.icon-boost-outline::before { content: "\f11d"; } -.icon-bot-command::before { +.icon-boost::before { content: "\f11e"; } -.icon-bot-commands-filled::before { +.icon-boostcircle::before { content: "\f11f"; } -.icon-bots::before { +.icon-boosts::before { content: "\f120"; } -.icon-bug::before { +.icon-bot-command::before { content: "\f121"; } -.icon-calendar-filter::before { +.icon-bot-commands-filled::before { content: "\f122"; } -.icon-calendar::before { +.icon-bots::before { content: "\f123"; } -.icon-camera-add::before { +.icon-bug::before { content: "\f124"; } -.icon-camera::before { +.icon-calendar-filter::before { content: "\f125"; } -.icon-car::before { +.icon-calendar::before { content: "\f126"; } -.icon-card::before { +.icon-camera-add::before { content: "\f127"; } -.icon-cash-circle::before { +.icon-camera::before { content: "\f128"; } -.icon-channel-filled::before { +.icon-car::before { content: "\f129"; } -.icon-channel::before { +.icon-card::before { content: "\f12a"; } -.icon-channelviews::before { +.icon-cash-circle::before { content: "\f12b"; } -.icon-chat-badge::before { +.icon-channel-filled::before { content: "\f12c"; } -.icon-chats-badge::before { +.icon-channel::before { content: "\f12d"; } -.icon-check::before { +.icon-channelviews::before { content: "\f12e"; } -.icon-clock-edit::before { +.icon-chat-badge::before { content: "\f12f"; } -.icon-clock::before { +.icon-chats-badge::before { content: "\f130"; } -.icon-close-circle::before { +.icon-check::before { content: "\f131"; } -.icon-close-topic::before { +.icon-clock-edit::before { content: "\f132"; } -.icon-close::before { +.icon-clock::before { content: "\f133"; } -.icon-closed-gift::before { +.icon-close-circle::before { content: "\f134"; } -.icon-cloud-download::before { +.icon-close-topic::before { content: "\f135"; } -.icon-collapse-modal::before { +.icon-close::before { content: "\f136"; } -.icon-collapse::before { +.icon-closed-gift::before { content: "\f137"; } -.icon-colorize::before { +.icon-cloud-download::before { content: "\f138"; } -.icon-comments-sticker::before { +.icon-collapse-modal::before { content: "\f139"; } -.icon-comments::before { +.icon-collapse::before { content: "\f13a"; } -.icon-copy-media::before { +.icon-colorize::before { content: "\f13b"; } -.icon-copy::before { +.icon-comments-sticker::before { content: "\f13c"; } -.icon-crown-take-off-outline::before { +.icon-comments::before { content: "\f13d"; } -.icon-crown-take-off::before { +.icon-copy-media::before { content: "\f13e"; } -.icon-crown-wear-outline::before { +.icon-copy::before { content: "\f13f"; } -.icon-crown-wear::before { +.icon-crown-take-off-outline::before { content: "\f140"; } -.icon-darkmode::before { +.icon-crown-take-off::before { content: "\f141"; } -.icon-data::before { +.icon-crown-wear-outline::before { content: "\f142"; } -.icon-delete-filled::before { +.icon-crown-wear::before { content: "\f143"; } -.icon-delete-left::before { +.icon-darkmode::before { content: "\f144"; } -.icon-delete-user::before { +.icon-data::before { content: "\f145"; } -.icon-delete::before { +.icon-delete-filled::before { content: "\f146"; } -.icon-diamond::before { +.icon-delete-left::before { content: "\f147"; } -.icon-document::before { +.icon-delete-user::before { content: "\f148"; } -.icon-double-badge::before { +.icon-delete::before { content: "\f149"; } -.icon-down::before { +.icon-diamond::before { content: "\f14a"; } -.icon-download::before { +.icon-document::before { content: "\f14b"; } -.icon-dropdown-arrows::before { +.icon-double-badge::before { content: "\f14c"; } -.icon-eats::before { +.icon-down::before { content: "\f14d"; } -.icon-edit::before { +.icon-download::before { content: "\f14e"; } -.icon-email::before { +.icon-dropdown-arrows::before { content: "\f14f"; } -.icon-enter::before { +.icon-eats::before { content: "\f150"; } -.icon-expand-modal::before { +.icon-edit::before { content: "\f151"; } -.icon-expand::before { +.icon-email::before { content: "\f152"; } -.icon-eye-crossed-outline::before { +.icon-enter::before { content: "\f153"; } -.icon-eye-crossed::before { +.icon-expand-modal::before { content: "\f154"; } -.icon-eye-outline::before { +.icon-expand::before { content: "\f155"; } -.icon-eye::before { +.icon-eye-crossed-outline::before { content: "\f156"; } -.icon-favorite-filled::before { +.icon-eye-crossed::before { content: "\f157"; } -.icon-favorite::before { +.icon-eye-outline::before { content: "\f158"; } -.icon-file-badge::before { +.icon-eye::before { content: "\f159"; } -.icon-flag::before { +.icon-favorite-filled::before { content: "\f15a"; } -.icon-folder-badge::before { +.icon-favorite::before { content: "\f15b"; } -.icon-folder-tabs-bot::before { +.icon-file-badge::before { content: "\f15c"; } -.icon-folder-tabs-channel::before { +.icon-flag::before { content: "\f15d"; } -.icon-folder-tabs-chat::before { +.icon-folder-badge::before { content: "\f15e"; } -.icon-folder-tabs-chats::before { +.icon-folder-tabs-bot::before { content: "\f15f"; } -.icon-folder-tabs-folder::before { +.icon-folder-tabs-channel::before { content: "\f160"; } -.icon-folder-tabs-group::before { +.icon-folder-tabs-chat::before { content: "\f161"; } -.icon-folder-tabs-star::before { +.icon-folder-tabs-chats::before { content: "\f162"; } -.icon-folder-tabs-user::before { +.icon-folder-tabs-folder::before { content: "\f163"; } -.icon-folder::before { +.icon-folder-tabs-group::before { content: "\f164"; } -.icon-fontsize::before { +.icon-folder-tabs-star::before { content: "\f165"; } -.icon-forums::before { +.icon-folder-tabs-user::before { content: "\f166"; } -.icon-forward::before { +.icon-folder::before { content: "\f167"; } -.icon-fragment::before { +.icon-fontsize::before { content: "\f168"; } -.icon-frozen-time::before { +.icon-forums::before { content: "\f169"; } -.icon-fullscreen::before { +.icon-forward::before { content: "\f16a"; } -.icon-gifs::before { +.icon-fragment::before { content: "\f16b"; } -.icon-gift-transfer-inline::before { +.icon-frozen-time::before { content: "\f16c"; } -.icon-gift::before { +.icon-fullscreen::before { content: "\f16d"; } -.icon-group-filled::before { +.icon-gifs::before { content: "\f16e"; } -.icon-group::before { +.icon-gift-transfer-inline::before { content: "\f16f"; } -.icon-grouped-disable::before { +.icon-gift::before { content: "\f170"; } -.icon-grouped::before { +.icon-group-filled::before { content: "\f171"; } -.icon-hand-stop::before { +.icon-group::before { content: "\f172"; } -.icon-hashtag::before { +.icon-grouped-disable::before { content: "\f173"; } -.icon-hd-photo::before { +.icon-grouped::before { content: "\f174"; } -.icon-heart-outline::before { +.icon-hand-stop::before { content: "\f175"; } -.icon-heart::before { +.icon-hashtag::before { content: "\f176"; } -.icon-help::before { +.icon-hd-photo::before { content: "\f177"; } -.icon-info-filled::before { +.icon-heart-outline::before { content: "\f178"; } -.icon-info::before { +.icon-heart::before { content: "\f179"; } -.icon-install::before { +.icon-help::before { content: "\f17a"; } -.icon-italic::before { +.icon-info-filled::before { content: "\f17b"; } -.icon-key::before { +.icon-info::before { content: "\f17c"; } -.icon-keyboard::before { +.icon-install::before { content: "\f17d"; } -.icon-lamp::before { +.icon-italic::before { content: "\f17e"; } -.icon-language::before { +.icon-key::before { content: "\f17f"; } -.icon-large-pause::before { +.icon-keyboard::before { content: "\f180"; } -.icon-large-play::before { +.icon-lamp::before { content: "\f181"; } -.icon-link-badge::before { +.icon-language::before { content: "\f182"; } -.icon-link-broken::before { +.icon-large-pause::before { content: "\f183"; } -.icon-link::before { +.icon-large-play::before { content: "\f184"; } -.icon-location::before { +.icon-link-badge::before { content: "\f185"; } -.icon-lock-badge::before { +.icon-link-broken::before { content: "\f186"; } -.icon-lock::before { +.icon-link::before { content: "\f187"; } -.icon-logout::before { +.icon-location::before { content: "\f188"; } -.icon-loop::before { +.icon-lock-badge::before { content: "\f189"; } -.icon-mention::before { +.icon-lock::before { content: "\f18a"; } -.icon-menu::before { +.icon-logout::before { content: "\f18b"; } -.icon-message-failed::before { +.icon-loop::before { content: "\f18c"; } -.icon-message-pending::before { +.icon-mention::before { content: "\f18d"; } -.icon-message-read::before { +.icon-menu::before { content: "\f18e"; } -.icon-message-succeeded::before { +.icon-message-failed::before { content: "\f18f"; } -.icon-message::before { +.icon-message-pending::before { content: "\f190"; } -.icon-microphone-alt::before { +.icon-message-read::before { content: "\f191"; } -.icon-microphone::before { +.icon-message-succeeded::before { content: "\f192"; } -.icon-monospace::before { +.icon-message::before { content: "\f193"; } -.icon-more-circle::before { +.icon-microphone-alt::before { content: "\f194"; } -.icon-more::before { +.icon-microphone::before { content: "\f195"; } -.icon-move-caption-down::before { +.icon-monospace::before { content: "\f196"; } -.icon-move-caption-up::before { +.icon-more-circle::before { content: "\f197"; } -.icon-mute::before { +.icon-more::before { content: "\f198"; } -.icon-muted::before { +.icon-move-caption-down::before { content: "\f199"; } -.icon-my-notes::before { +.icon-move-caption-up::before { content: "\f19a"; } -.icon-new-chat-filled::before { +.icon-mute::before { content: "\f19b"; } -.icon-next::before { +.icon-muted::before { content: "\f19c"; } -.icon-nochannel::before { +.icon-my-notes::before { content: "\f19d"; } -.icon-noise-suppression::before { +.icon-new-chat-filled::before { content: "\f19e"; } -.icon-non-contacts::before { +.icon-next::before { content: "\f19f"; } -.icon-note::before { +.icon-nochannel::before { content: "\f1a0"; } -.icon-one-filled::before { +.icon-noise-suppression::before { content: "\f1a1"; } -.icon-open-in-new-tab::before { +.icon-non-contacts::before { content: "\f1a2"; } -.icon-password-off::before { +.icon-note::before { content: "\f1a3"; } -.icon-pause::before { +.icon-one-filled::before { content: "\f1a4"; } -.icon-permissions::before { +.icon-open-in-new-tab::before { content: "\f1a5"; } -.icon-phone-discard-outline::before { +.icon-password-off::before { content: "\f1a6"; } -.icon-phone-discard::before { +.icon-pause::before { content: "\f1a7"; } -.icon-phone::before { +.icon-permissions::before { content: "\f1a8"; } -.icon-photo::before { +.icon-phone-discard-outline::before { content: "\f1a9"; } -.icon-pin-badge::before { +.icon-phone-discard::before { content: "\f1aa"; } -.icon-pin-list::before { +.icon-phone::before { content: "\f1ab"; } -.icon-pin::before { +.icon-photo::before { content: "\f1ac"; } -.icon-pinned-chat::before { +.icon-pin-badge::before { content: "\f1ad"; } -.icon-pinned-message::before { +.icon-pin-list::before { content: "\f1ae"; } -.icon-pip::before { +.icon-pin::before { content: "\f1af"; } -.icon-play-story::before { +.icon-pinned-chat::before { content: "\f1b0"; } -.icon-play::before { +.icon-pinned-message::before { content: "\f1b1"; } -.icon-poll::before { +.icon-pip::before { content: "\f1b2"; } -.icon-previous::before { +.icon-play-story::before { content: "\f1b3"; } -.icon-privacy-policy::before { +.icon-play::before { content: "\f1b4"; } -.icon-proof-of-ownership::before { +.icon-poll::before { content: "\f1b5"; } -.icon-quote-text::before { +.icon-previous::before { content: "\f1b6"; } -.icon-quote::before { +.icon-privacy-policy::before { content: "\f1b7"; } -.icon-radial-badge::before { +.icon-proof-of-ownership::before { content: "\f1b8"; } -.icon-rating-icons-level1::before { +.icon-quote-text::before { content: "\f1b9"; } -.icon-rating-icons-level10::before { +.icon-quote::before { content: "\f1ba"; } -.icon-rating-icons-level2::before { +.icon-radial-badge::before { content: "\f1bb"; } -.icon-rating-icons-level20::before { +.icon-rating-icons-level1::before { content: "\f1bc"; } -.icon-rating-icons-level3::before { +.icon-rating-icons-level10::before { content: "\f1bd"; } -.icon-rating-icons-level30::before { +.icon-rating-icons-level2::before { content: "\f1be"; } -.icon-rating-icons-level4::before { +.icon-rating-icons-level20::before { content: "\f1bf"; } -.icon-rating-icons-level40::before { +.icon-rating-icons-level3::before { content: "\f1c0"; } -.icon-rating-icons-level5::before { +.icon-rating-icons-level30::before { content: "\f1c1"; } -.icon-rating-icons-level50::before { +.icon-rating-icons-level4::before { content: "\f1c2"; } -.icon-rating-icons-level6::before { +.icon-rating-icons-level40::before { content: "\f1c3"; } -.icon-rating-icons-level60::before { +.icon-rating-icons-level5::before { content: "\f1c4"; } -.icon-rating-icons-level7::before { +.icon-rating-icons-level50::before { content: "\f1c5"; } -.icon-rating-icons-level70::before { +.icon-rating-icons-level6::before { content: "\f1c6"; } -.icon-rating-icons-level8::before { +.icon-rating-icons-level60::before { content: "\f1c7"; } -.icon-rating-icons-level80::before { +.icon-rating-icons-level7::before { content: "\f1c8"; } -.icon-rating-icons-level9::before { +.icon-rating-icons-level70::before { content: "\f1c9"; } -.icon-rating-icons-level90::before { +.icon-rating-icons-level8::before { content: "\f1ca"; } -.icon-rating-icons-negative::before { +.icon-rating-icons-level80::before { content: "\f1cb"; } -.icon-readchats::before { +.icon-rating-icons-level9::before { content: "\f1cc"; } -.icon-recent::before { +.icon-rating-icons-level90::before { content: "\f1cd"; } -.icon-refund::before { +.icon-rating-icons-negative::before { content: "\f1ce"; } -.icon-reload::before { +.icon-readchats::before { content: "\f1cf"; } -.icon-remove-quote::before { +.icon-recent::before { content: "\f1d0"; } -.icon-remove::before { +.icon-refund::before { content: "\f1d1"; } -.icon-reopen-topic::before { +.icon-reload::before { content: "\f1d2"; } -.icon-reorder-tabs::before { +.icon-remove-quote::before { content: "\f1d3"; } -.icon-replace::before { +.icon-remove::before { content: "\f1d4"; } -.icon-replies::before { +.icon-reopen-topic::before { content: "\f1d5"; } -.icon-reply-filled::before { +.icon-reorder-tabs::before { content: "\f1d6"; } -.icon-reply::before { +.icon-replace::before { content: "\f1d7"; } -.icon-revenue-split::before { +.icon-replies::before { content: "\f1d8"; } -.icon-revote::before { +.icon-reply-filled::before { content: "\f1d9"; } -.icon-save-story::before { +.icon-reply::before { content: "\f1da"; } -.icon-saved-messages::before { +.icon-revenue-split::before { content: "\f1db"; } -.icon-schedule::before { +.icon-revote::before { content: "\f1dc"; } -.icon-scheduled::before { +.icon-save-story::before { content: "\f1dd"; } -.icon-sd-photo::before { +.icon-saved-messages::before { content: "\f1de"; } -.icon-search::before { +.icon-schedule::before { content: "\f1df"; } -.icon-select::before { +.icon-scheduled::before { content: "\f1e0"; } -.icon-sell-outline::before { +.icon-sd-photo::before { content: "\f1e1"; } -.icon-sell::before { +.icon-search::before { content: "\f1e2"; } -.icon-send-outline::before { +.icon-select::before { content: "\f1e3"; } -.icon-send::before { +.icon-sell-outline::before { content: "\f1e4"; } -.icon-settings-filled::before { +.icon-sell::before { content: "\f1e5"; } -.icon-settings::before { +.icon-send-outline::before { content: "\f1e6"; } -.icon-share-filled::before { +.icon-send::before { content: "\f1e7"; } -.icon-share-screen-outlined::before { +.icon-settings-filled::before { content: "\f1e8"; } -.icon-share-screen-stop::before { +.icon-settings::before { content: "\f1e9"; } -.icon-share-screen::before { +.icon-share-filled::before { content: "\f1ea"; } -.icon-show-message::before { +.icon-share-screen-outlined::before { content: "\f1eb"; } -.icon-sidebar::before { +.icon-share-screen-stop::before { content: "\f1ec"; } -.icon-skip-next::before { +.icon-share-screen::before { content: "\f1ed"; } -.icon-skip-previous::before { +.icon-show-message::before { content: "\f1ee"; } -.icon-smallscreen::before { +.icon-sidebar::before { content: "\f1ef"; } -.icon-smile::before { +.icon-skip-next::before { content: "\f1f0"; } -.icon-sort-by-date::before { +.icon-skip-previous::before { content: "\f1f1"; } -.icon-sort-by-number::before { +.icon-smallscreen::before { content: "\f1f2"; } -.icon-sort-by-price::before { +.icon-smile::before { content: "\f1f3"; } -.icon-sort::before { +.icon-sort-by-date::before { content: "\f1f4"; } -.icon-speaker-muted-story::before { +.icon-sort-by-number::before { content: "\f1f5"; } -.icon-speaker-outline::before { +.icon-sort-by-price::before { content: "\f1f6"; } -.icon-speaker-story::before { +.icon-sort::before { content: "\f1f7"; } -.icon-speaker::before { +.icon-speaker-muted-story::before { content: "\f1f8"; } -.icon-spoiler-disable::before { +.icon-speaker-outline::before { content: "\f1f9"; } -.icon-spoiler::before { +.icon-speaker-story::before { content: "\f1fa"; } -.icon-sport::before { +.icon-speaker::before { content: "\f1fb"; } -.icon-star::before { +.icon-spoiler-disable::before { content: "\f1fc"; } -.icon-stars-lock::before { +.icon-spoiler::before { content: "\f1fd"; } -.icon-stars-refund::before { +.icon-sport::before { content: "\f1fe"; } -.icon-stats::before { +.icon-star::before { content: "\f1ff"; } -.icon-stealth-future::before { +.icon-stars-lock::before { content: "\f200"; } -.icon-stealth-past::before { +.icon-stars-refund::before { content: "\f201"; } -.icon-stickers::before { +.icon-stats::before { content: "\f202"; } -.icon-stop-raising-hand::before { +.icon-stealth-future::before { content: "\f203"; } -.icon-stop::before { +.icon-stealth-past::before { content: "\f204"; } -.icon-story-caption::before { +.icon-stickers::before { content: "\f205"; } -.icon-story-expired::before { +.icon-stop-raising-hand::before { content: "\f206"; } -.icon-story-priority::before { +.icon-stop::before { content: "\f207"; } -.icon-story-reply::before { +.icon-story-caption::before { content: "\f208"; } -.icon-strikethrough::before { +.icon-story-expired::before { content: "\f209"; } -.icon-tag-add::before { +.icon-story-priority::before { content: "\f20a"; } -.icon-tag-crossed::before { +.icon-story-reply::before { content: "\f20b"; } -.icon-tag-filter::before { +.icon-strikethrough::before { content: "\f20c"; } -.icon-tag-name::before { +.icon-tag-add::before { content: "\f20d"; } -.icon-tag::before { +.icon-tag-crossed::before { content: "\f20e"; } -.icon-timer::before { +.icon-tag-filter::before { content: "\f20f"; } -.icon-toncoin::before { +.icon-tag-name::before { content: "\f210"; } -.icon-tools::before { +.icon-tag::before { content: "\f211"; } -.icon-topic-new::before { +.icon-timer::before { content: "\f212"; } -.icon-trade::before { +.icon-toncoin::before { content: "\f213"; } -.icon-transcribe::before { +.icon-tools::before { content: "\f214"; } -.icon-truck::before { +.icon-topic-new::before { content: "\f215"; } -.icon-unarchive::before { +.icon-trade::before { content: "\f216"; } -.icon-underlined::before { +.icon-transcribe::before { content: "\f217"; } -.icon-understood::before { +.icon-truck::before { content: "\f218"; } -.icon-unique-profile::before { +.icon-unarchive::before { content: "\f219"; } -.icon-unlist-outline::before { +.icon-underlined::before { content: "\f21a"; } -.icon-unlist::before { +.icon-understood::before { content: "\f21b"; } -.icon-unlock-badge::before { +.icon-unique-profile::before { content: "\f21c"; } -.icon-unlock::before { +.icon-unlist-outline::before { content: "\f21d"; } -.icon-unmute::before { +.icon-unlist::before { content: "\f21e"; } -.icon-unpin::before { +.icon-unlock-badge::before { content: "\f21f"; } -.icon-unread::before { +.icon-unlock::before { content: "\f220"; } -.icon-up::before { +.icon-unmute::before { content: "\f221"; } -.icon-user-filled::before { +.icon-unpin::before { content: "\f222"; } -.icon-user-online::before { +.icon-unread::before { content: "\f223"; } -.icon-user-stars::before { +.icon-up::before { content: "\f224"; } -.icon-user::before { +.icon-user-filled::before { content: "\f225"; } -.icon-video-outlined::before { +.icon-user-online::before { content: "\f226"; } -.icon-video-stop::before { +.icon-user-stars::before { content: "\f227"; } -.icon-video::before { +.icon-user::before { content: "\f228"; } -.icon-view-once::before { +.icon-video-outlined::before { content: "\f229"; } -.icon-voice-chat::before { +.icon-video-stop::before { content: "\f22a"; } -.icon-volume-1::before { +.icon-video::before { content: "\f22b"; } -.icon-volume-2::before { +.icon-view-once::before { content: "\f22c"; } -.icon-volume-3::before { +.icon-voice-chat::before { content: "\f22d"; } -.icon-warning::before { +.icon-volume-1::before { content: "\f22e"; } -.icon-web::before { +.icon-volume-2::before { content: "\f22f"; } -.icon-webapp::before { +.icon-volume-3::before { content: "\f230"; } -.icon-word-wrap::before { +.icon-warning::before { content: "\f231"; } -.icon-zoom-in::before { +.icon-web::before { content: "\f232"; } -.icon-zoom-out::before { +.icon-webapp::before { content: "\f233"; } +.icon-word-wrap::before { + content: "\f234"; +} +.icon-zoom-in::before { + content: "\f235"; +} +.icon-zoom-out::before { + content: "\f236"; +} diff --git a/src/styles/icons.scss b/src/styles/icons.scss index f779cff39..9b0906817 100644 --- a/src/styles/icons.scss +++ b/src/styles/icons.scss @@ -35,292 +35,295 @@ $icons-map: ( "arrow-right": "\f111", "ask-support": "\f112", "attach": "\f113", - "auction": "\f114", - "author-hidden": "\f115", - "avatar-archived-chats": "\f116", - "avatar-deleted-account": "\f117", - "avatar-saved-messages": "\f118", - "bold": "\f119", - "boost-outline": "\f11a", - "boost": "\f11b", - "boostcircle": "\f11c", - "boosts": "\f11d", - "bot-command": "\f11e", - "bot-commands-filled": "\f11f", - "bots": "\f120", - "bug": "\f121", - "calendar-filter": "\f122", - "calendar": "\f123", - "camera-add": "\f124", - "camera": "\f125", - "car": "\f126", - "card": "\f127", - "cash-circle": "\f128", - "channel-filled": "\f129", - "channel": "\f12a", - "channelviews": "\f12b", - "chat-badge": "\f12c", - "chats-badge": "\f12d", - "check": "\f12e", - "clock-edit": "\f12f", - "clock": "\f130", - "close-circle": "\f131", - "close-topic": "\f132", - "close": "\f133", - "closed-gift": "\f134", - "cloud-download": "\f135", - "collapse-modal": "\f136", - "collapse": "\f137", - "colorize": "\f138", - "comments-sticker": "\f139", - "comments": "\f13a", - "copy-media": "\f13b", - "copy": "\f13c", - "crown-take-off-outline": "\f13d", - "crown-take-off": "\f13e", - "crown-wear-outline": "\f13f", - "crown-wear": "\f140", - "darkmode": "\f141", - "data": "\f142", - "delete-filled": "\f143", - "delete-left": "\f144", - "delete-user": "\f145", - "delete": "\f146", - "diamond": "\f147", - "document": "\f148", - "double-badge": "\f149", - "down": "\f14a", - "download": "\f14b", - "dropdown-arrows": "\f14c", - "eats": "\f14d", - "edit": "\f14e", - "email": "\f14f", - "enter": "\f150", - "expand-modal": "\f151", - "expand": "\f152", - "eye-crossed-outline": "\f153", - "eye-crossed": "\f154", - "eye-outline": "\f155", - "eye": "\f156", - "favorite-filled": "\f157", - "favorite": "\f158", - "file-badge": "\f159", - "flag": "\f15a", - "folder-badge": "\f15b", - "folder-tabs-bot": "\f15c", - "folder-tabs-channel": "\f15d", - "folder-tabs-chat": "\f15e", - "folder-tabs-chats": "\f15f", - "folder-tabs-folder": "\f160", - "folder-tabs-group": "\f161", - "folder-tabs-star": "\f162", - "folder-tabs-user": "\f163", - "folder": "\f164", - "fontsize": "\f165", - "forums": "\f166", - "forward": "\f167", - "fragment": "\f168", - "frozen-time": "\f169", - "fullscreen": "\f16a", - "gifs": "\f16b", - "gift-transfer-inline": "\f16c", - "gift": "\f16d", - "group-filled": "\f16e", - "group": "\f16f", - "grouped-disable": "\f170", - "grouped": "\f171", - "hand-stop": "\f172", - "hashtag": "\f173", - "hd-photo": "\f174", - "heart-outline": "\f175", - "heart": "\f176", - "help": "\f177", - "info-filled": "\f178", - "info": "\f179", - "install": "\f17a", - "italic": "\f17b", - "key": "\f17c", - "keyboard": "\f17d", - "lamp": "\f17e", - "language": "\f17f", - "large-pause": "\f180", - "large-play": "\f181", - "link-badge": "\f182", - "link-broken": "\f183", - "link": "\f184", - "location": "\f185", - "lock-badge": "\f186", - "lock": "\f187", - "logout": "\f188", - "loop": "\f189", - "mention": "\f18a", - "menu": "\f18b", - "message-failed": "\f18c", - "message-pending": "\f18d", - "message-read": "\f18e", - "message-succeeded": "\f18f", - "message": "\f190", - "microphone-alt": "\f191", - "microphone": "\f192", - "monospace": "\f193", - "more-circle": "\f194", - "more": "\f195", - "move-caption-down": "\f196", - "move-caption-up": "\f197", - "mute": "\f198", - "muted": "\f199", - "my-notes": "\f19a", - "new-chat-filled": "\f19b", - "next": "\f19c", - "nochannel": "\f19d", - "noise-suppression": "\f19e", - "non-contacts": "\f19f", - "note": "\f1a0", - "one-filled": "\f1a1", - "open-in-new-tab": "\f1a2", - "password-off": "\f1a3", - "pause": "\f1a4", - "permissions": "\f1a5", - "phone-discard-outline": "\f1a6", - "phone-discard": "\f1a7", - "phone": "\f1a8", - "photo": "\f1a9", - "pin-badge": "\f1aa", - "pin-list": "\f1ab", - "pin": "\f1ac", - "pinned-chat": "\f1ad", - "pinned-message": "\f1ae", - "pip": "\f1af", - "play-story": "\f1b0", - "play": "\f1b1", - "poll": "\f1b2", - "previous": "\f1b3", - "privacy-policy": "\f1b4", - "proof-of-ownership": "\f1b5", - "quote-text": "\f1b6", - "quote": "\f1b7", - "radial-badge": "\f1b8", - "rating-icons-level1": "\f1b9", - "rating-icons-level10": "\f1ba", - "rating-icons-level2": "\f1bb", - "rating-icons-level20": "\f1bc", - "rating-icons-level3": "\f1bd", - "rating-icons-level30": "\f1be", - "rating-icons-level4": "\f1bf", - "rating-icons-level40": "\f1c0", - "rating-icons-level5": "\f1c1", - "rating-icons-level50": "\f1c2", - "rating-icons-level6": "\f1c3", - "rating-icons-level60": "\f1c4", - "rating-icons-level7": "\f1c5", - "rating-icons-level70": "\f1c6", - "rating-icons-level8": "\f1c7", - "rating-icons-level80": "\f1c8", - "rating-icons-level9": "\f1c9", - "rating-icons-level90": "\f1ca", - "rating-icons-negative": "\f1cb", - "readchats": "\f1cc", - "recent": "\f1cd", - "refund": "\f1ce", - "reload": "\f1cf", - "remove-quote": "\f1d0", - "remove": "\f1d1", - "reopen-topic": "\f1d2", - "reorder-tabs": "\f1d3", - "replace": "\f1d4", - "replies": "\f1d5", - "reply-filled": "\f1d6", - "reply": "\f1d7", - "revenue-split": "\f1d8", - "revote": "\f1d9", - "save-story": "\f1da", - "saved-messages": "\f1db", - "schedule": "\f1dc", - "scheduled": "\f1dd", - "sd-photo": "\f1de", - "search": "\f1df", - "select": "\f1e0", - "sell-outline": "\f1e1", - "sell": "\f1e2", - "send-outline": "\f1e3", - "send": "\f1e4", - "settings-filled": "\f1e5", - "settings": "\f1e6", - "share-filled": "\f1e7", - "share-screen-outlined": "\f1e8", - "share-screen-stop": "\f1e9", - "share-screen": "\f1ea", - "show-message": "\f1eb", - "sidebar": "\f1ec", - "skip-next": "\f1ed", - "skip-previous": "\f1ee", - "smallscreen": "\f1ef", - "smile": "\f1f0", - "sort-by-date": "\f1f1", - "sort-by-number": "\f1f2", - "sort-by-price": "\f1f3", - "sort": "\f1f4", - "speaker-muted-story": "\f1f5", - "speaker-outline": "\f1f6", - "speaker-story": "\f1f7", - "speaker": "\f1f8", - "spoiler-disable": "\f1f9", - "spoiler": "\f1fa", - "sport": "\f1fb", - "star": "\f1fc", - "stars-lock": "\f1fd", - "stars-refund": "\f1fe", - "stats": "\f1ff", - "stealth-future": "\f200", - "stealth-past": "\f201", - "stickers": "\f202", - "stop-raising-hand": "\f203", - "stop": "\f204", - "story-caption": "\f205", - "story-expired": "\f206", - "story-priority": "\f207", - "story-reply": "\f208", - "strikethrough": "\f209", - "tag-add": "\f20a", - "tag-crossed": "\f20b", - "tag-filter": "\f20c", - "tag-name": "\f20d", - "tag": "\f20e", - "timer": "\f20f", - "toncoin": "\f210", - "tools": "\f211", - "topic-new": "\f212", - "trade": "\f213", - "transcribe": "\f214", - "truck": "\f215", - "unarchive": "\f216", - "underlined": "\f217", - "understood": "\f218", - "unique-profile": "\f219", - "unlist-outline": "\f21a", - "unlist": "\f21b", - "unlock-badge": "\f21c", - "unlock": "\f21d", - "unmute": "\f21e", - "unpin": "\f21f", - "unread": "\f220", - "up": "\f221", - "user-filled": "\f222", - "user-online": "\f223", - "user-stars": "\f224", - "user": "\f225", - "video-outlined": "\f226", - "video-stop": "\f227", - "video": "\f228", - "view-once": "\f229", - "voice-chat": "\f22a", - "volume-1": "\f22b", - "volume-2": "\f22c", - "volume-3": "\f22d", - "warning": "\f22e", - "web": "\f22f", - "webapp": "\f230", - "word-wrap": "\f231", - "zoom-in": "\f232", - "zoom-out": "\f233", + "auction-drop": "\f114", + "auction-filled": "\f115", + "auction-next-round": "\f116", + "auction": "\f117", + "author-hidden": "\f118", + "avatar-archived-chats": "\f119", + "avatar-deleted-account": "\f11a", + "avatar-saved-messages": "\f11b", + "bold": "\f11c", + "boost-outline": "\f11d", + "boost": "\f11e", + "boostcircle": "\f11f", + "boosts": "\f120", + "bot-command": "\f121", + "bot-commands-filled": "\f122", + "bots": "\f123", + "bug": "\f124", + "calendar-filter": "\f125", + "calendar": "\f126", + "camera-add": "\f127", + "camera": "\f128", + "car": "\f129", + "card": "\f12a", + "cash-circle": "\f12b", + "channel-filled": "\f12c", + "channel": "\f12d", + "channelviews": "\f12e", + "chat-badge": "\f12f", + "chats-badge": "\f130", + "check": "\f131", + "clock-edit": "\f132", + "clock": "\f133", + "close-circle": "\f134", + "close-topic": "\f135", + "close": "\f136", + "closed-gift": "\f137", + "cloud-download": "\f138", + "collapse-modal": "\f139", + "collapse": "\f13a", + "colorize": "\f13b", + "comments-sticker": "\f13c", + "comments": "\f13d", + "copy-media": "\f13e", + "copy": "\f13f", + "crown-take-off-outline": "\f140", + "crown-take-off": "\f141", + "crown-wear-outline": "\f142", + "crown-wear": "\f143", + "darkmode": "\f144", + "data": "\f145", + "delete-filled": "\f146", + "delete-left": "\f147", + "delete-user": "\f148", + "delete": "\f149", + "diamond": "\f14a", + "document": "\f14b", + "double-badge": "\f14c", + "down": "\f14d", + "download": "\f14e", + "dropdown-arrows": "\f14f", + "eats": "\f150", + "edit": "\f151", + "email": "\f152", + "enter": "\f153", + "expand-modal": "\f154", + "expand": "\f155", + "eye-crossed-outline": "\f156", + "eye-crossed": "\f157", + "eye-outline": "\f158", + "eye": "\f159", + "favorite-filled": "\f15a", + "favorite": "\f15b", + "file-badge": "\f15c", + "flag": "\f15d", + "folder-badge": "\f15e", + "folder-tabs-bot": "\f15f", + "folder-tabs-channel": "\f160", + "folder-tabs-chat": "\f161", + "folder-tabs-chats": "\f162", + "folder-tabs-folder": "\f163", + "folder-tabs-group": "\f164", + "folder-tabs-star": "\f165", + "folder-tabs-user": "\f166", + "folder": "\f167", + "fontsize": "\f168", + "forums": "\f169", + "forward": "\f16a", + "fragment": "\f16b", + "frozen-time": "\f16c", + "fullscreen": "\f16d", + "gifs": "\f16e", + "gift-transfer-inline": "\f16f", + "gift": "\f170", + "group-filled": "\f171", + "group": "\f172", + "grouped-disable": "\f173", + "grouped": "\f174", + "hand-stop": "\f175", + "hashtag": "\f176", + "hd-photo": "\f177", + "heart-outline": "\f178", + "heart": "\f179", + "help": "\f17a", + "info-filled": "\f17b", + "info": "\f17c", + "install": "\f17d", + "italic": "\f17e", + "key": "\f17f", + "keyboard": "\f180", + "lamp": "\f181", + "language": "\f182", + "large-pause": "\f183", + "large-play": "\f184", + "link-badge": "\f185", + "link-broken": "\f186", + "link": "\f187", + "location": "\f188", + "lock-badge": "\f189", + "lock": "\f18a", + "logout": "\f18b", + "loop": "\f18c", + "mention": "\f18d", + "menu": "\f18e", + "message-failed": "\f18f", + "message-pending": "\f190", + "message-read": "\f191", + "message-succeeded": "\f192", + "message": "\f193", + "microphone-alt": "\f194", + "microphone": "\f195", + "monospace": "\f196", + "more-circle": "\f197", + "more": "\f198", + "move-caption-down": "\f199", + "move-caption-up": "\f19a", + "mute": "\f19b", + "muted": "\f19c", + "my-notes": "\f19d", + "new-chat-filled": "\f19e", + "next": "\f19f", + "nochannel": "\f1a0", + "noise-suppression": "\f1a1", + "non-contacts": "\f1a2", + "note": "\f1a3", + "one-filled": "\f1a4", + "open-in-new-tab": "\f1a5", + "password-off": "\f1a6", + "pause": "\f1a7", + "permissions": "\f1a8", + "phone-discard-outline": "\f1a9", + "phone-discard": "\f1aa", + "phone": "\f1ab", + "photo": "\f1ac", + "pin-badge": "\f1ad", + "pin-list": "\f1ae", + "pin": "\f1af", + "pinned-chat": "\f1b0", + "pinned-message": "\f1b1", + "pip": "\f1b2", + "play-story": "\f1b3", + "play": "\f1b4", + "poll": "\f1b5", + "previous": "\f1b6", + "privacy-policy": "\f1b7", + "proof-of-ownership": "\f1b8", + "quote-text": "\f1b9", + "quote": "\f1ba", + "radial-badge": "\f1bb", + "rating-icons-level1": "\f1bc", + "rating-icons-level10": "\f1bd", + "rating-icons-level2": "\f1be", + "rating-icons-level20": "\f1bf", + "rating-icons-level3": "\f1c0", + "rating-icons-level30": "\f1c1", + "rating-icons-level4": "\f1c2", + "rating-icons-level40": "\f1c3", + "rating-icons-level5": "\f1c4", + "rating-icons-level50": "\f1c5", + "rating-icons-level6": "\f1c6", + "rating-icons-level60": "\f1c7", + "rating-icons-level7": "\f1c8", + "rating-icons-level70": "\f1c9", + "rating-icons-level8": "\f1ca", + "rating-icons-level80": "\f1cb", + "rating-icons-level9": "\f1cc", + "rating-icons-level90": "\f1cd", + "rating-icons-negative": "\f1ce", + "readchats": "\f1cf", + "recent": "\f1d0", + "refund": "\f1d1", + "reload": "\f1d2", + "remove-quote": "\f1d3", + "remove": "\f1d4", + "reopen-topic": "\f1d5", + "reorder-tabs": "\f1d6", + "replace": "\f1d7", + "replies": "\f1d8", + "reply-filled": "\f1d9", + "reply": "\f1da", + "revenue-split": "\f1db", + "revote": "\f1dc", + "save-story": "\f1dd", + "saved-messages": "\f1de", + "schedule": "\f1df", + "scheduled": "\f1e0", + "sd-photo": "\f1e1", + "search": "\f1e2", + "select": "\f1e3", + "sell-outline": "\f1e4", + "sell": "\f1e5", + "send-outline": "\f1e6", + "send": "\f1e7", + "settings-filled": "\f1e8", + "settings": "\f1e9", + "share-filled": "\f1ea", + "share-screen-outlined": "\f1eb", + "share-screen-stop": "\f1ec", + "share-screen": "\f1ed", + "show-message": "\f1ee", + "sidebar": "\f1ef", + "skip-next": "\f1f0", + "skip-previous": "\f1f1", + "smallscreen": "\f1f2", + "smile": "\f1f3", + "sort-by-date": "\f1f4", + "sort-by-number": "\f1f5", + "sort-by-price": "\f1f6", + "sort": "\f1f7", + "speaker-muted-story": "\f1f8", + "speaker-outline": "\f1f9", + "speaker-story": "\f1fa", + "speaker": "\f1fb", + "spoiler-disable": "\f1fc", + "spoiler": "\f1fd", + "sport": "\f1fe", + "star": "\f1ff", + "stars-lock": "\f200", + "stars-refund": "\f201", + "stats": "\f202", + "stealth-future": "\f203", + "stealth-past": "\f204", + "stickers": "\f205", + "stop-raising-hand": "\f206", + "stop": "\f207", + "story-caption": "\f208", + "story-expired": "\f209", + "story-priority": "\f20a", + "story-reply": "\f20b", + "strikethrough": "\f20c", + "tag-add": "\f20d", + "tag-crossed": "\f20e", + "tag-filter": "\f20f", + "tag-name": "\f210", + "tag": "\f211", + "timer": "\f212", + "toncoin": "\f213", + "tools": "\f214", + "topic-new": "\f215", + "trade": "\f216", + "transcribe": "\f217", + "truck": "\f218", + "unarchive": "\f219", + "underlined": "\f21a", + "understood": "\f21b", + "unique-profile": "\f21c", + "unlist-outline": "\f21d", + "unlist": "\f21e", + "unlock-badge": "\f21f", + "unlock": "\f220", + "unmute": "\f221", + "unpin": "\f222", + "unread": "\f223", + "up": "\f224", + "user-filled": "\f225", + "user-online": "\f226", + "user-stars": "\f227", + "user": "\f228", + "video-outlined": "\f229", + "video-stop": "\f22a", + "video": "\f22b", + "view-once": "\f22c", + "voice-chat": "\f22d", + "volume-1": "\f22e", + "volume-2": "\f22f", + "volume-3": "\f230", + "warning": "\f231", + "web": "\f232", + "webapp": "\f233", + "word-wrap": "\f234", + "zoom-in": "\f235", + "zoom-out": "\f236", ); diff --git a/src/styles/icons.woff b/src/styles/icons.woff index cdbd4c2e2cd2b9e330300ff032b78ffd944b31ff..6ed95509aa28d1cbc0f061ecb9c1f6aa1f4ee710 100644 GIT binary patch delta 38557 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 delta 37967 zcmV)PK()X4v;vH<0u*;oMn(Vu00000m<#|5000019|(~YKYz1hZDDW#00D>q00n*k z01_-w51R^SYVC0018V001Nd#{o8IZFG150E?gi002Dz00huy;Q#e(Z)0Hq0E^%N00L?N00L@l zPcjB=VR&!=05*v@NZQB~#wr$%sdTiTvk8RtwJ*UU)dse@H<5tA8SLTk)tc;4<8C5_Fpm~$=O&Xdu z@1mNvXf~s1wr0;ar|s8KVf6#Qrmb9WZZJN$& zM|(QZkxq1`3tj0(cY4s1Ui799ed$Mk1~8C83}y&J8OCr%Fp^P>W(;E)*Yy4qn8+k1 zGli*4V-DtIF6L$)=4C$SX8{&uAr@v47G*IOX9<>MDVAm#mSs7XX9ZSdC01q?R%JC- zXARb5E!Jio)@41`e`f)0*Ks{Ja3eQy1T(iVgOl(AqErp6K{dFB z)X*AM!)rv1tWh<(#?;svSL16!O{_^Zxu(?An%49+Ysvp#?HxMqksUvk#tPSFW3#|E z57&5OL%3QSTZHSsv1MRe1-5ly+XS|4_*|3g12ccXzzz!R;J^+E?9jjt3+(W~jtK0? zz>W&+=)jH%?AXAL3+(vtS>8AyuoDA2DX^0RJ0-AF13N9Sa|CwIz|IxexdS^-VCN0& ze1V-munPos!N4vQ*o6bTNMIKY>|%jkJg`dycFDjl71*T%yG&r04eWA(T|TfY1a`&1 zt`vXRl>@s7FcEiAK6xfXeyGdX- z4eVxt-8`^c1a`~7ZWY+A1G`ONw+-xef!#i^I|O#e!0r^-oddf|V0R7dZh_rBuzLh{ z&%o{#*u4Y0Phj^A?0$jWKd=V`_Q1d%6xe@*1A9nd4-M>LfjvC1M+ElBz)lbBQGq== zu*U@U*uWka*y96xLSRn}>`8$=Ik2Y$_SC?h7TD7Rdq!Z-4D4BfJv*@H1oqs(o)_5j z1A9SWFAVHOfxS4emjw3Gz+M*E%L98wV6P19Re`-au-63k+Q42H*y{s(Ltt+V>`i}x zy*aSA1a?MXZw>5ifxSJjcLes%z}^+uy90YqVDAm=eSy6{unz?G!N5Kg*oOoANMIig z>|=p_Jg`p$_Q}9L71*Z(`%GY;4eWD)eLk=+1op+iz7*J(1N%x~Uk&VQfqgx&Zv^(u zz`hmOw*&i5VBZbwdx3pFupb2W!@z%j6xfdg`$=Fw4eV!u{XDQ=1oq3oeihiS1N%*2 zzYXknf&D(PKLqy2!2T52#=y=D?9YMyC9uB+_P4vIC>+peQ>y$_|OL zL!<1lC_6mLj)<}&qwJ_CJ37jaiLzs(?6@d9KFUsrvJ<21q$oQ%%1(*0Q={y(sA>NL zDfnOE004NLw7m(mB-vFM7;k@%Ju)L>$vuB&{-62(uU~)5t*Wc*|5|!eSJUc!Q*UaO zq}JZ8T}aguh)t~)7-7m12mu14!5q^9W5#D-@SKBYXf(#m0m%brju$b;_`s2Dg9bxu zEX}>|Mdr`yssI4d&6QD{E-!sSl?m2+4?Tas`P*NdMYGJ=4q0* zNuHe|X}>2E_}-t62gk@{WWIaDZ8996CgaHgnN8uUZrvhDwm*flcy-Xvp`DWOFU@lN zcZy7B@DHyK;IcZ!vb;rQMEb+Q4w=lRx6(+438RFtB$UylB9sz`SX6ZNv5+a3QdhC? zgStwTYg65Jodila0&ah$@TGzh9x;aXHla0qCS^57^k0SWB#@;$N-{_|sVPsv2fqlx zXWx#`#&&p+2-_B^Y5BB%-Yb`XNFT5oJp4lOaHvq2R`$(r!rX2VWgW9_wq9ddYXcnh zd`jRS%vNqDW*;VSq~``_XF43KewxVM;56y?1_$I6nT)6VFuQ-F{Vb6=oEyWGPZYEm zACdz-@%mDq4DG-Uoa%E`2gWD4?#~scbSHnhDQ(#hl1ScwT9Zrp*q)GzM>ew+t5L~R z1Sk2QMN*h&getVFXKQw#^eL`F71-7DnHxONz&nfQn94rrBK0)Dj17hp(_lIq!Bh-!tT+jyrwGRCb*&peb9B?NTv*{rzcE|#Q?2v)#g(PX4E~=%a`4J}F zQvnCy<97RrwykTyDR-3LkauyuI?DGBBB>Z`2r7SJu2kHW!t;de#&FlwO#2urIO=I*G|s{lEH=FvhBpC)czX$Y9_d{Rq3V# zc40Y$d2%a^!XK-+Fl%Ai3GC#i5;Wl=;}0n>^i-5YwV)cnCvCN0Iz@p?V#~KuYtuSo zy$XNUs<%zdh?9^EVa3`6CL!+)rZa%P0ia;O3~k&+GKZ#cmcpEk7bjJ3Fwv-7>KU7i z5z(0WdrQ)wccvoEo{PV+p#&39{0n*<11V;%1UKYE^+1ZN}45XN2n}% zb(8^km7C>P!+-nfq^BPQ#rs?9P14$EK5c({OvPzMa)40gwmU7Ct#Uv-!C+%8WO%Z? zGu|z;n_&LaG(w0iwMy`j%9466j+44|qxG!yPp#jue#`m-Kp6B~W%+E{CICWdqV#rC z{SdK7vDpR_Jt?DnIs>c<4FIw_cw)ap5WZk)06P$9)Pwl}@Pe`f#8APEg+QdTym)_T z8>r!|c<6MdB+Tw1f%da00;L*t7~XPV&~}<2WQSyXe%Qv=!@(3$oxx-Md1cn$`?D}r zLU6$yDum)T;-)k{d(+uC!K%ZhkW>lDg>X`zNuEl^{E}CW8Ra5}%OrI}0HZi`RRjow z`HC>kR`qRt!aMkwsI;@YQwp)V!byKm|JWL|0)omodDs(x<0b3>K>=krrLt1xl7qxn zz=IaYwWoZ(!vCO8l^~-Kg|KO7G{&W51r5 z#;_Ao6|Y8jh>(d_dLG@x%Kd+ohW)s?T_>SW=mX4C{D@vwpr5HV#GbAJcx@Bhv(O9V zwvaEI4B?;$$Pk8sfDA(c;8e3|J_7I_^x*+csuJ%VULsSwm0nI;x05yQ@F7zUZ#Oy2 zaqTjoBHMerF9W6iAo7~F<2j8W`UoJP^gOg?18m0HEx6}ZBz9m$%X)trJ>ACy`j|r> zC)RD&?baREJ=O!(!`7qL6RmpT5TyuSkRl#gKoHp&n843SmEEIJXtoZhFzjaL6Btf`;SWN<#N(e9+TwIC5e_ zN)Gw3uya^4dEDXKxLtUzV6RZT-_}q0|8GumY@KHz*`e6HO(H~MYHyOxcGX_GyO+LHdAX$sERKeR(t`SC8`h7K8jS1K@4}HDLqh@&SM2Q=YvTG>)s`n{hoG22I<$ zHS(S^!-}R%13C_5paK8Q#EvN~+hnmPfp4@z;Fu757#3t-qX?>&amft%KG={)y`KW9 z0Wxs8x>>Dm?rwip!&>)4t7KwW^gBKS!JC79VE9?1k|et-6p_jBp;8#E7m9wv)$ z_5jS(^nSfB&i^oQ!%}?w983lfY5o9bOV7?>+`w)0<_~|Hj(6sK;!kqh<@a;=xHdoc z!-$H1_>U2z!3nN$;dvk=SN3x@9KbAgknvP0uD-&fY#;kS{L7c^(94XV;6V|;x2;nk zecf$61`r3okmgCIDZ11|7(RJ6f|Y|wQu}QRM7}q~F(ESwmywA=zDO0M0qJ-CGWE-A zhXdd{DA0d7>clHP$U-0>+G~ev@ac@&q%-P-A)&qyb}E=B2&<&+Q6Oy37C=J}h2uKH zD|rX=Gi0TAs?Tf3${_G6w`2pq#Zm6;ox1T<56JCor^%_y8K=P70yd6@d2^@vT98NK z19aKGMs3dTyCkzt!kiqSxP^#BqC^iv-q!~x{Of0z(yg(TQ!uA*!kBu0-v?7HDFyd$vfTDKeQ>b2V`@9y+`ki9I|^W1nhe$?~ALAZm< zx2-A)R_+nE?ZT7p^1Hp7qx?O*v>W?=|M>ATcG(CkL(+s@cfvYn-2@o*0qY{}Ke^C5 zAYOks(n1XSa4lDZ0z`+i+yLq9gp7b68BrFlPd93CL^&S4`;ZCA4u4Va z2NdjHk%TUOyBz*ZElhqt4$hEr6`m6Z&KZ966emyuES&TLA1F(TldXFX>f)r zPS3pBc5V0+a9;=BxU1p*PU}s;Gr+L=sMEn&C{z!6sX>yOj8W}?%xZ2H7jYCWeDR%U zg={d}pY^j*K0nCk7!FuglzrQDAN4?ll}Q zhXDKZH1K?+_) z6>&-d@Kyl(^|TqbDH31N+N{7FDfq<>k-%X}QUhkS2Af1UzV86jX)59eZsb8JwC%7I z@EbV`qzo7@=#=$E>kmQNU$v$nXIXzU6b`g9VnL>+v#Y4oR7(*1%Tx-`2r@9k_gx3V zB@3L}oq&4MyXkhW6vyHWbUp|OFw|w}YD`AgNhbJRAXNULTNdJ0HwfHU2vK%{+Y{#y zY|aVUrv&B^wtShwE#ee1@Wjw0>pv0K8d=wC>e>rY*aoUJ+k+KC8CoN}12TWF>9hG> z2I~eR*rvG=K!BZ?S1!jZHDFCa2B9Dqus{eQZ775-p$Om*dVB=k`GGEpaj%r!E$em9Lv46kN z2qZAH6rgz6(>j3RKpCw;U&4QUk0*V~{kmKB&Ut0G?t|pd?LfLR?s1%Y(T(9C073TW zyQTrMIp&V;V^zoJE>WV~;wU}vR#_CT^e zVgFhD(ht#(0?4F@q+-R;uu7sdABlR?Xxgz@Sh8Hav;!q+4;7xQ;%hWavBuJeW8>fa{9C9pJc` z(0$#|J`aB!3h<$1MTsEkCJmB?8$wF44*U8L+BYj_r5JJ`4#Oy`S9&QxuliBK&LUUm zo~N&ABoR`pu+jop!Y8`Qlt*@f72wn#x1NMK>Hxc$&y0+lsVqN4p$c{(K)FG#g;H*Z zXa(O~1vk`yKLTQLr0D~G#pps8avI>2Axzvf-zI-=CXwItBh93iTp78mR4B&zDkno6 z-H{SbF!EZBphO=@bCpM> zvY+?_1Ow^=@rM-&fu1{#AVIa!sQQ#UE?z<1eGmX%aACH6DLpsDK3=G<@2=-L6xB6X zIgWpF3!3y-)?ZsI)}}Q>VGA8sS>_kx5F|NfZR$@K7IxoDEUq$OOeoG@{;bV3%hfw;a(ed z@`X(Ypmer`okqH28kUbb*8dVneSVaYB>I2l5X%Um_@WYn7o_+lxE4GQ1=KZQrqL%N zV8Wn4=z|psd|^LxKf>M5NHJIws?bGjk;LkQ{GfN_Y_v3G+Cqc#HW~JhIyoI89|%oS zl=%jQZU&I2!nT_Fk8%TX~DLxK6=(sl>~qK z4y&(33I}J)%E_?zZ^w=Gb{tz4OQ&CImCLOz7Ufcwb+YUt-Y>54;Lk~T;#oZxhj^(H zOSt|~tm5u}4(1fj9F$uRzBY$Z)svSOZKrGfw0DY!~A1xw5@Ag39wo07{s5Y7&o zh}BDm-_}_8S3MQOFtX@*=z6IVEAM~I87L~K<$oTzq{LJE<)SxwfCT!Jk&245(ns(f zC}LHMq3N@tC@NPE0RHR+UTIis)^Y2s^&QrO*4wT3fK;T>ZogPeB;?3nwo&TdH|^{$?AvAlDtB-fQ5x zMgtLfWL|kjve@sjFpfh?dVYV*B)LH?@O5H+-HNP=)&;#(AOhBR0{>rp0UvD&_KJpSx{A?LvD`S~ls7Du2IKc~u&@QD_e%<$!d_UK^L z*2Pn6XV%uv+=>O-LQ7e-oG2%7TpO)@SqT=RynN2Jv-0ImadUh0^TmI?P#}2}9;=mk zx#~y`;-!s~Tdpw&A=+KK;@R4gRbxjyr%k$mhbD756SYyxE)qR0*&HiaU@iFQ2{}yw zqJV?BdA$-%Dj?7J%7`(_M@eTIRn|+*5`1hFbBQAx(s|h52)TrHwez3OZBIa#!VSOF zSZS74i74AB4%@i`Iof|d!rzKiVej;{t_bHGSj-)=AS_5$5z#4a)S69ZT6fkT7`+LM zXA1ap@F&2pIptWLP9h3WS#64bZFGzCUPRLuYPof?5L{7Py%1fqx&Mb=R%7nQE{=1;RDjU;R0d_Bw5x_Wl|SIw%1%5W(zc-F zy5}<6lSeJ2XJ>z-#VN|MB?ke>7IQd*l>-cTAM~m)s%ulPhPWIdZoDw5qq(vV%Qm~J z@3`e&uJ5-KV!CmIsQ`$fl+gr;yE*n(qrZ>dJ>-1 zeC+B+q(`TgZd>TXiL$;7xXPLhj`Yf?ygnsDE)JQ;o<)D9^@l!=w!1^lpG9@`hvs&R zD&bbi+P2PEcNE%2g+O#jjEM%-%7A_{5T*)s@kr}b4-oC=L#-o68Bwd7r{kG28X{Dv zqNedOmwhH3w#FoH@3+^x+y?DWhg`0~bNVNJ!fczk+pXG0wcFr~+Pu4dNlk*Hk1lCM@(6{q6^Ti16qGj-&vuzHGWY;V{Ji?fQVc^!uM;P zQHLNN??7e3fGO|yfwyM;zNsTf^vTK*hJUeW48`rs4NYC}Q1q=itYAL_=;x+&-7+=X zrjskF*-N>oE00Hmqn~{GsOQ&#V8Svqao@{?U@0B~Q8MjdNS$YoI(;W+7xDTP#bQ5L zUxj~v={}>4`Jo#V^Fwd05!#VjWj&cvE(q-tIzIGD`ssEBDhq#J z;W+SH#`6c22YX8*9*P^1J6eAU+W!aXj(neSmO~|Ci7vH z+NdQ?S5ed3_sb;@L=Xa;c-oUha4)XqP)DzF~AvPt8{s+Ud-34 zD;dkWDCd&69)sjz!#$0Ri^ia?&sKlBgOv)Yt&j^+++0G_9*Ee3xw}F6CheqV^z#21 z{*{2f?_1|_4m9>%c&m-_BQsDj7k_JuAK)P7ijz?CNB_3!j|+YdzfZym_gknJYlgmq zRn*_E;Vf%oijl|7n!v^z7AD~b|5s9pxH3X>~^(=@Tp&N+2mF%m+#xX3MNeT`XpweeD92jZM?ElW<8#whRNUVGnp)7xak|^bh1@Utz z;K(43gC7klmEag>z3*6Itd?(bxkR0>}fhMJZ@i2Pf;XBNuEleL_N4=0EB2fJWZyP>04nMJbOM3 zl;~+Vi_@?}$_@xv09~*Pq*K26%EOyd!lU~D3nBsFOZBA*c_%*S9r4kG5GFjh_sv&6 z3J*Qxpc_a_D1Ub8sqg2M75qj{O4dMonBNUJMx!;rb$NeyK#YG}41-idJU92!005Zf zqlgTlG0enN>n1eK%#CVehvZ8x|HNWIh{_({+ysa&d(eYu0(+Z(o&o!l(bqd$UG-6? z1iWaa0^PTT6L~fZXy`l$=b{@wh0^e+01EyY-0hY4CX*3RHrN9!9;4&vZz2lGID6DR zzU9trUU6)|TFifsy}Mn{Vc|A_Bz%tW*B0=mLv87_DtffV$Y%ZFXlBNpz@W8h&Zq_= zKyJw(m$>amYLpxOW5OH|7$OF2PQ?w&dD-6DQck&Ac2t%Iw}My`x|KIveE)II z-x*aI>2T$+Z~O&=ax3>xi9TB00`70#Z(J+S znpp=%UoxNJ+0_fypX#nJEy`ix;*3MgNB{R?QX7t089(v?d8{AfILT)EpK}B1vXrax@T;3W43<=)?kCF2p>oBSZ+Z&@HWxzGb0`F>0nnx8?w zXqe2K6^+J=CP_#E)f=XKFw9^L^1Zf^fB`-R)7gI>p2?YB-tVS-`dVqRDAeTvf$) zy0|nsFTKX?4Nr2n_zpeKDXl!PQgVDkd{g}=^NT{lp%lMZe9uq+YbktR0D1R{@5~P_ zg}$r8P`Q41DKOP1xT~*oUS})}89U%K3@Lwau;M;8hhGA8qk{Zb1qk{TkxUqX)LRZS zfD5zzMSQ`ae@Sp>gvk2Wu^7Q_c_T=tKnxpc0v#r zl)4~${OTKY-MTs^=8kVOCMLg@;8{2@zkEo{eTew(yD}t(^DIL-6iSdovrO*)<1M26c)?!)>j16jZ|MN|2kyx4U}^@QnQh|-44Z?RBu*E0)<=?q5aCUE0x_Ay)l0jw0uye z;}uR@yZ>mf&2H)+?7foYN{s;8J_Z~+6qz$ps&;J1#b6-#u>ShjzxTbbU$Pk{)^VWj zZvx0llXS5?QxiNS`+9~A*3mixtu+{-9SX7b5KaH+Tl_M?c6y^<6-YE3Jd2YLG&0`M zESRgRXREe*#FM#p^_iYt1z3L)Z{ppn;;?2%Zmh8}An4eQ?Ap1-DM|qlXMwU`+*q)a zNmVUBap@->DA>#%gGaxKUgLSiDW@97Xdi?}bCeIRj5B=4-!aZG3(*Bc83%jZe?}nC zLLpk*=RyPk#*w3wT(+$s@TA{j+~Fq~>N8s{>VR<3?E?RMbo2qBS&DxjaOpWc+fgMT z5w+*(pF=&%1Au?HH;o46kh!SEb@?%Q2rCVM_W}sf@7q8xJcplw@(g;lZ@yRS zM$B*jF7TFt*61zNp3nz1G>El8vzNyl@ZZV`_icU;7GrawIp)BScRJkm`1`OJn-c{M z?GewN|7}!k2DmM5)g* zK#Mm2IXiKaBq?92Tp}v56Z_{h$1o7=v+68dh~dHl?`eB#%Xq$B>Ar!{kvnAJwt-O~ zhvX|uUJ<|XN+)&ioO?vjyQRGM#U%QmZt)>#u{)7O%-(;Y9SuG@50NtQwNUn71legOV%f0EqD8HZvt`)tlua*AVVFQI1dWd1}U^m0Z&4;X=(_} z{&={Dmo(MTXP~)G1fcd1E;5vh5CVpJ-|FXR1-ce$oo1? zz+f`op@TXabm+-*kF)?G11$tDE3a_aT+twD9yY~sDZY1iO?rgLQbm@j4I3|uI8A~7 z0ivKHN0i@cW9%S?B{nW>Bo$g=zVssDWSb>Gj;YO1+sL2vLSU43sXN1<-&)y@fxeU} zk*IZ#{4Po8}kJ0oeDiE>lgz9TCgJMhVtpa*gwftPXeK$JP4CqKlWri}O) zxkw_JDJB_3FS_9d2idA(e41Oi6f##BnF!JejZ&NMpmjY~WlTZHr+TxX@GT zXzy2H=TEdxF=AHS@Up+KUE_*rBl}PeCPRODWZ=db?hmIMKpK9V!x(wL*{;>nN(tEK z1}BGMt?AY6pf2|7)hsSm0&m3XG3!Ks325+h4D%hodhZN)Xx;05pBv%Y4zz!49uQ(6xXTTv?lX2x$kF(%=`Lc-K$9?f!%3yBiJ6E1&z zGV66}S+`RSE0t!YT-q9RW5&w8wTA}XGGnFQ;CR1Pji8pdZ)`RKxRy5`Upd}w!(AEN z0-x(^`I@rV@_IcRCcZ*cIL6;oq3=Sbg77C9wH82Q+a0i1GI`6erz}y zOb>PNP1d10T!jqICg@Th$Xjm}f+|Ilv%m&9>b@QoR0gbjA23paeD>tMnBRf19+XY@$ zI;IKa(aLp*-OyF95FYk(Ba45+nSv?q0j4vSN0Y_GNM^Hqo8a()a~QcG(M&^KPMjt+l0pA5C>WM8E- zoqd6z6%`u{dOsrL^-2VSJu6j5xhf4}U^1~gJRhHC$!4tJy3O<5OqK`0l{)}u@VSKS zgUftw6Z>K9i}ObU2));Rf=K8cv|_KJHur#=p3};VM6ly7AgxqMOUJkZQ5+BFGK!vW zS_muoWN5A&qjSL}y;^@}YcQDI=r9jNIV^IvSM$N)e(Y?ym1czmO@g3{0EE~AN9qZ7#&3d4~g~*BY=aqb7 zELw|^jF!|)5H!yE1t^0m5br?gK@ut=3Wsg9!o{j-+(q)9`ic zzv@`hWh0{QN`{QeNSpXxY-~@r8>jwA*G_V(5Kgr@3_V6ci9R@te(c4h!=sADYlX`;ofrX+|t!Wqos`<5` zSE+5*$|c4zrvfjBHYXs;z`5|2W)4h-x7`CwU5b4V)re(|$rxb6mcQ%=*)U61JQ_+6 zV*ylcR1D>VywtwAy6%DmndJR3OpRp7VgMY2up3fuWiF?}3TE0rMQ3IjO=lC_hA4~; zRgthM$&-JVXbdJ(?W2Kl=+I(}EBC)JOp$aOhL?IP=m$eIGy$`goJ*7^HF&{Zr2HSj zApbR&F=9CvDFm8$0G-}Od7dhCU)1=|m##{4P7QLUb6unLr?AhO)|T;ZFSeE{lyKPV z{=nD-wS9AJP|F@n{&3#-J>?8IhU|3Uyv+#&1g; z&Q(EF{wX*KpH~Fsa#i`Z51%Ew8|Dd1VYDZVC%Cr0bcm5}c94IXhehgTn4t>>#?$um z!v6$?pm+IBlh7N06p&`}OXln3)Qtl7mmGhXD)&auX;S(g)QJ2N>PARKwV=s6Fu)}F z1eCSF{e+Gvc?Yy7c9UK}VF>>(`k9a_aHpB|M$OF-W8@zJGBCR@&HF>cv@R*gjP7#; zGTi7&)u6#>C|&LwHLk(e#=9oeq4kD$_?TcL%3X*0=X}JVBL;HGRu2(p8OVlK(ZYXr zq{k_BUh@*AttZRaF7lU@w&jbi>&RFi_@qMB2ZY19Xtfk@a~}Z6983>%#fKiQExnc1m*vvfh2BW_ORHEX)Ul`>V^h{ZQWO-I@^?^e^4f3SUY%mXi9xVk! zF9$~JJRNgQ;m{}rjqWR7YPAmlZVP`OeE~*Td<50_ACYqp{>%EC=u-#EwDSwnqYu7p zQZSj%Are7XU6A_t2168&n`?7i4LqiGOlKHFDK^zbf(AiDq z)SA0Oy$Cp4rM%molw9GEN|nV9a7cvTEpX`kf{Uhodi$+%RjO6GTWg?(!NBh-tb+@Z z%0O#HwAO4o=!*eXwZ;R$xZ8^gUwFKjfhc!Lh)d9)Z@kDkeHU{nc^6<1O5e$d%icx# zAKBytr6-8p0$%M`fcRZvoB)3o9|O6#B&qlnjD$4$1cz(__SgVk`gZH>%Q3DvYntpG z1-fdhk8#64z^pSm8G=y^!@OUItf@wf1EV2Cj~=5bEHsA6LN&Pf1~m1BRxdAoqLlYq z^UA$Wb-n7UPbjy#-d(Cc2_*3hrDwPUROXB<$umGbKJK-A2Goc7Ep&f0aF|^j;7OY~ zl3$Ka_RH03xqmWR)OdZXhCX+-t$J49sw>Y^@b!LrjM8I_+78>|e2Y2u7d($jN#Qbj zKmgy#Ja{nhkIG%x$E+6t3zxNL|4l~`SxY`SS89e#d{I^;ygO1S&AGw8(Ig8sz#Xv< zfd4Bx%x8pna;ScOUx$C)870!^^tM>Ty>&^60d5PqzpOZdXI#SXHN07CnDi6nn%+K3 zF^dV{`kSqLtna*5WFZsuy9k!)mvD@uHu{t{dn6yi(DVki>uHONT!>YO@%oI_Wur zp{ZPY4&dUD6WuP74q;go*Xv}Zs-LcZq};8BwdIGK%8eM8qa53Wlkw}62jv<4pfkX> zQWu3XN&s$vCYTPWuu@;G7qLez;zMl(_A*B89$4qBTlB6rHqyK>d={z13e`Pkp}=Sm z+%CX~4M#(5fXjb6RKYf!DL6CJHo4!+yWQ<>SEUpUA5{$VsWK`YmNL?+Z-=_8$_D(p+g-gyhVX`tlskK_H@-NO`EZq6m}jOaz4aOZueiScwS~z^1JNS&C@|0_EFn>S9r`)ZlI{TTiDAIz zxCDtlasWl14-y2K3nW;0jXXjtKq;^L$bWfh04SW%IQsD@2DI+I!3{k|oY=G3-OP;u z_1kXj{6l{cV9Gub5-!f-YTIWd4|L`Zz%PJY{)a%YCkd+|%S)XGrL^q=R-n8E>^xNz zIQbSP9LyOA@RHTozliKOmcYm7sAkTAO_y^g-` z+lmCG2jRi?O@gP`p_Gf8K+tnVC|oH1-h~oy0knT)bLc4uIxu8p0GbRw+N4ootOe3U zi7xEqRyd8My+F`ZqJ0&}NJ|XJyjh~XXB?H5LlCBv;EGj%S z0%xOLqHdkC&H&cF3w_Kc!xS~}fSQNM{>&9Ahh(Uwx$%*m*mwvsEy$yf;3)#QTBSoB z#E0o!TIBy6)yF_NJ&_{9lXfL^zE}AJ8%UoMN6z=ahGB47arH&X@ZU$yNoVvlyWxN4 z`$vFNJTaQoZUbh-b3T*`M}ChJ#c;X|`zCU}S07-A3R6H!zo;1O!H=9{-_ucwoUcB} zDBLzZ@;xbAEo&Y4lN$l&ER8~%Ac48E2rb-2=lc^?%mm2ZK(Epn3@@aZ&p0I&7(mJX zzR;`KFa$j?)48Xyg8eS7l&Gq|!TaWd_dg#A( zzN4RTe>&$+hrnYEtk)sVgr%8G0RWXwJ2}uY)SyV;VqET~17$qi_7_o(h34prI!2lr z)BO>hE-sP8O{GiX5J*I+QesL4fMx=_Gj2QWQLx7C&jSGf$pC>>YLHdHQ`mpJPEfnt;nVXS76%}9IDvh!J??aycYE0}TfPP}8a*U!TfP|sPu`5R zS1~|v-v@lg1oQu}yRv$1qk0j;Sk6j&VOz7lV*NF6?dOZEA_ZNXr`iNgbhL*lI7YKY z_B-6jYW`j12}A~B1~l?@5@dgh4DoZ_(P^A(7+r)X`wr%pBzBHxn|7+(*aTBd;x)-@ zeY+2C}~RvVFC0S^y;Wm-xMOt_57g?2qPQ)x@gQNG<+i3}xl_{tqV%9bJE1SE`ptFYi?W zk2vZ&WJK_5=!eNd2UaEwB$Hi$TOHD@sk})Tj%XEkojEr{sd(;6s7-<-AW12yRw{8)g$iNy z)+uK5>s$4m>S$C=sqcRV-7<4|IW7gRPsryhO$Cfc7;-=ttx9igV+}xOZDWx4S62G% znqTH1hI1A%E_vCn&Gmq~k2S5`l9~rW#XfQv^PZ@`Y+cW7cB)lpx=Tr1sT5uMK=B)E zy-G{Ye_S=;$Cu)}Fb=JceB8Ao8iDHE&PG({ zT5;cdMQV91R?WM=9B+tyoBd5ueEBu=c^AUowL|#owpat)q2;&%AQBM5UM_;~S+Qsa z6+lpfqkP@gA6Z}3y6!6xpiX{*XmcA$_?J*BjK?v`d1rt0I>h6O$prBg>Drf!ZxOi! z#X@(6x#K+8-}k_?my#QrAlF>Yk(YKyKTUKH)+{@q6P;ypZ#qL>eV`e31tfQ(v#;oY z*hEWp|3UeIFT*ri1JO%7$aHLwQ^jx@+etS2m3-r5olu!by9~TQ<<)M*uKM-0*vW(V zcNTfL&*gs`)i8XJ!QF~EAY8zhs;-i?L0a9&KUPPjSee)&#e^46fUH+>oV9W6U~aLX z&?$e_igezfv2_|`^jBIBSg*F;XuZSwfc3qF#J(It^V0kVOAcPMtFk!vuS&wRs0{xu zjlY6<9G=&yGIU~$=Yf3AuyR4m>uBV$?G>TbU@L#-=-uY%m^r%XZ*TIIv~&@F=3*(W z+TtQU{i3iRFjKv@oTlgMa3jl<`xY5g?(OR5cLiXKG)~K&Ed4-5{*1#qusg$;aVj z1$KYisnvEVO-pUMdJ>Mlievr~z~fGfs{rt2YX=TqlQIgTTi({P{z^t&48WoDebNF5 znpt=1eKH&s;g`ou#K|ImK2SoCI#Gf}E7>BYsj;W)D6Ar9TA`md(Kj&Uy#M2MvJzHt z*MkJ2E?^fw7}P_TGFxEmSP;*2tfb4QE#`lqPs~}HOS(q{2DB3Ilt(28nG()OJK1Jee{VUE-!KPJu&H*K_{ez~=FGn}dw=-JEx)bKdMvtv}a$ z=B2yis_5l+AzQbJ#pOlq&jtTElyR>pj_}#ntpA2tlV`@KPCw@HAL9InxZ}L|2z7ty zBk+v>NeJu62di$af}Ep0<#4+Um(_{J(XzKq4YAevDm4)vXcbF-lmKA<3XS(g4G(3H za3gGm&Gj%scks|_v>K`Bxh=2pa6640H)@B2wGdq-b;I^B4AK29bQ}M>hY^n~gtP0d zFoI`c0ECw|+6}Medbg+1U=XxJ$2EU9gso`33ETxXbC+mhMjATG9iykMnVyWKy~xX| zlds~z%;+_GI*;erBxyC##Ca+xC;A6lL3liz{R1cuXlGw$Uo$y}(E-is!(l9|cRS<{W=Gt16^4ovIwLzGg za~p6u)j6;5x)hj?;bwuUw1$*94r@|wqr#LGvfHBls+2EA;i$`W@_1OQ-(Gt`W3wJ(-x)u+UG9&+>G38FitdGG%6h^?#O%2i*)h7){@l(J~h^;JdTc9 zk5?LZcCu-<}$!wAk5yOwMY1=1=c4GDbwxx?4Nu-qV6DK`O0OGil5T$lTb; z^qGYb^xQs|a*UBVEuHAA#a*?Kq0tx7a;ysap{KK9+D}K5ygyMnresR*zqG%9x%P}M zzckq2A6(eKWWKEB_aaVHZgS{?|gAgR7N@wkG?IUj4g-?{G)`F+S+%M=GKSW-B$v`>D2Ui>w)=sqE z50rQTf8Yg-$*~vpKpQE4U(n^33>zg5jIWK@FPNVBZ+=t1tEFeMHC&wpZn%`SdhqGy zZnL?20*j^*UNAhtmhv0LSty>9$acxsNpXm-%7;Q)SNv8@M`^x%u9m$ka^| znCHW7ELJc_FKMBUk14+N`<0>r6c4eJ95X>on#=|+gcfj9wf>!d_UE>a)KH6;Qe1f= zzx_#SD?;A}_wS*L&wGxJ%b20{b??SFNA@8`=pKXq(2b)LWqqRH8~#fF<`uuFb3H!u zdWOD1Pr(>=8L&WCKk;b4px$&<`##PC$5TUnM#hqGs8d@NQ9?s?3WFew=X5^=>NwF& ze(xD4bkK(fn26(ll)k?N>{n=;_d-wtXfOQ8_c0Ic?J%*n_^<-X+CZy3$G4H$a4&)t zNBcbmgo;@x-;e?SR)PjK26wy-eM8`GM(RHiV~T?Xd=o9R)wMV7+@lQO*?80!>B6+g zlFnaKP`s5!6|yVHwd3id#uRh{6@#V7j^8BgY;9{T!&gRsZ8iWV8=E!t<-FU?53zVO z4i2H$FyzA^zEg>OEz8z&%vYw$PsCit5>FqfJC zo0gfU+V+Z=x`?V+pz;p+7b4Qu!wp~pHq9HsLOJ_ODQxYI^6?FT_f7L6g3sAXOqcDY zMu)PeA!)9EFaR35$Y2a(9A5qMfSF0Uz4Ri1C4InBp1JqT)fp#rg?N$o)FNS@n%{7x zwqb3d*RZcqoAWB4v%X&VeOw{)r%QEZkcgIRo}ZgU7N(JfT>j-n?cPQ0t@CCJ9=Bxu znf|?1jNqUBjeaF_SCT7Up0RkThT1^9{42QBzk;=Y520B6FeC5VKBe3x-$2VO8gVRs44@-b7-d+b0GjIW6NeuS+GDh+AllICb zNl9(E{>s`f*owOWVJxL2yxWcTBN7O-xI04abSAYV0^w3&6wsGZ>gnZb_nC4$NxFgm zQ?)=wNp0e~*|=3b#8)#N#X@`yxR;*JlaOhDuY(?9^&$*0Gr6ptr>)>GC8Fz4K4Fq_U3*-VRn zP|RiTvpMIzH(SKAqIrA&ie&d!IIT|xlPg%6^yMHh1A50@;mGpcv2>(|Ue4^!7=R~2 zmrKrl2}FhMVr-UhRQaA5Gelw_mp&omd&y*m_OicsKRir-Nx7*rFNrSJ)l%#gu)$WWxvEqa-dy9tl_;Gp zs^Gx1FqyoPF4d=ip^O({Bk>suc<8YGGAvU4k4Od#6SK!KE$*1_Yt*^rG z8JRRBMRqi;e)>FTw_zCO`Ew>N^CtmrZqpLs`Ex)#@EtXC+dAn3C)l>88lp#ksL#S^ z@ggWw??|9@=)HhgZpv-hb>scG?c_YGm&rrS>#L;E zNb0J8Jjblk3%v|EPCV;gZH+^J{zuyti?`mPi`;%z$gl@=zj#sO)VwWi-yF^L()zV{ z=rn1bgSr^{xKbRD15jH{tP`$mE&|D@esL(^ywKsyrnX>`O3Lj>atDZU2@zz)ca;x3 z5(wk53+I)vJ%E_DQ}Wi*l73-h5DO^-XC+*j)S7kaC((}FPlATiazfXCQFXeGD75Ua zigYbZN^vb2Z)D?hNr}z}^_S6$vy^VH8M7Y+xr{Y=jD z0UMp=QKoAYEavZ8JRnDE-{p{_{?msI8`Io>G>DzXnQ_7>dluaclULX-^?LLsyDWbvARQ=*KA0f@EFcHJP*nfU$4>(;7F`0y~sJjttmfYbDBZLK4S ze#u}0{AZX(k&EOeX&dhZm^f$`rD5UEv`IEWO5d~2Td#mwd8KtHLdP1aVv6^1>a3s$ z3l#O48s`m_QPQAN3Z1(;R7aths3!BKrHI)a*?OT*nF2>NAV$L!@5!)1eIVZb>{1WfU&#b zihXxbv5xX0RJ8u}dYwP$3f1fIrDkOld@)i+6?iyzg3%Yhd>PdsSp35LU1_d;GZ&nX zPoj826+MYTVuG_;JGl&?fW-@;cL`fw^1>Pi`ga187Q(-O>qgk{7A8zTzxhqT(Z{U> zY~Kblp#D6PY7v=yxIi0}wnV=FVT_ z`d+vGBS7{s^!=Y9(Lx-b8)5r~7;;lXY_?kz& zz^%I(!2a4ARVs7Rc9pS^+AQNg#uN(~t9B@Vof~*vS&G z4!*TUQ*IoSegXG3#e7#eW(q9cE`omM7}yJcThzQyV|Y)P0>9+0W<9aymwRDM^3sV% zPjZq*KO%UScKRFuO^8ncze-CjAX`LoQi+3J$zSj1tP5Bc<|{Adgr9u$M3j@~32#Lp zUF1TNAG5_;m#%Qp<&rGt8H%h7IKERw2J&UA>`=d$N53@sZ%b`>WJ}%0z`o7L)~O(W zo#t4oF8)r0R9MJjXKYbpB_YH@CSf)F}7uEag$^-6qtJ5Rn{jRMppdaD|b@bkvy7s$7o6KW67tcJ(V{Y@tNjK2b zHxZ|&=lbtMs+j?3sEi{x-UJv+rzA*KB6U#4NQa%7&>@gWmmdEqZFGGvqOLE00_fu_ zx}ul{?hrjDfaQrJMyZSWTbzU9)fUk7cV7V_gQS=Yk6Z*Qk68p6x9xZ8CJ$hf`=$1I z_*@W&HcRY06mCe?^z{Jz&}Z@V*jamToFhli~$jW%^BI0qRSCgYaD(^=EjAh zSod!b%ru5?nmk43v4_Rm%Q0(z(Oj)HESBB81sZo9?7LI+fb5v`l#}6jGKLxKr^c7H zNXrpX49CvjbbqKoaN<-{L5OYJzyy2JJz=}*qzmGmpmrO?(kk+YAcSAHs}m;hnvQk^ z4ml_9$}xltM0zS}_>MDi1EwwzvCCz;N?ER?mqS~vUq66mxhGZ5Xg`yG+>He#pMl-O zE1W8ass=FVQlx~Wj7sQALs3WRt6aww8NO(h3}FA_`&-y%W*yO-a(FU0X(S#wsLF7s8p^8`yB%H@oZ z8DJU^-lr;#OQOENEATFV0<#uKxGR#!1vwVl8&eQi-P#kp)l@#~5=N)`{k=x^!Mv+I z%-s9({lzHw446a4SM3eqi_O#A=a{4OU{i>}2G4j+ zAgeHqLTLCZvzJP*JaNR<@uSyl1g<)(TwT0>*h(*A3n=u}i&%`0 z;Z-c~=a1f(f_Z4RL0-MxdYkn@>!apv^IC~va{fq=2zA(7o6L_+lfi-Zca$l(sgx=39w41 zZA?9A6X`2_zluD=ndi!YNG}u)CHo-iQozX!_6h7PyR@-?z0oNHS@8oX(!u_T{b6d- z?v@)HGELQn%__lNL4`E|+uwzL6x3mJy~JOT0R1H@Oa2ny@zb3DGo?%NR3}s9tQ!}ZDYl7v z@})W%=3b?fG5f3pvRV^p^y8@29qsMsdpIE&w!UZH-#Nmwu*FXUbQW4AWsLUbWvRxM z=YVMEQhWo-JXmx#0ih@Br}Ni*ynwVCDC{dhOyXUCq|!i7@*f}wn~w-rJc287P~ee)5jk(83}AR&Q`v_F<~g@_rk+g0G=7mAA!f(O43zI zSGmHcrJY9H4NG-LzlOVB3cGQ=oqU#%uvP8Wn&mPXuE8VA{>=DhEV2&IA}O1`z21~%(Hc5l z6AnFR*b-&gT(|wC*V|ouegI!-J*(jhtyh4H{rPL((lifzLu={Q*D_lWcA^STI994HzeeW(`*iLVGo7Jv=~`!5-0rvIsxRwR2j3i2>;24CXMQVgm&@&c zxH8?X`nF&5t3k-tYS%i6{9+NO)3+Kx=kK-tzV#{e<=O`hW*=l#U>C>zVGkIa9xyX7 zqe+fO2tjZplaXn8NOVhl`5Ru;P4VI`aLn_^L}WHXpVGd5AKOf86pjH2*6AvDOtRG3 zaD;Hzp~I2F96u4&57!A%bRtW?N+kh*=C@91l_JYnV;^c$K;6Wq9SR>)ZS$X~0Ug1X zHA6^^T2)=ELS@9n5+tU&OR|CWnj!pt=l>n64L+{qwPG% z{$81Zbjbd{*1kMQw(G3#p8f7y-=+8N>7MDHc{6Y3&Ghv2dz!b(($g}MEE#Kmv9M*Z zRzG=>LAJrMY_M#_av2Dw`~oBtNer$cE=NIxEr4S~K_KK0l8OssLM2KisZfMeh#dnq z*!jM5@9pV%i)BHidAIL=&pr2??|k2PzVG*ozoy`+6z32m+>Ak4#IM1_DAh%LM&5omElSBl@HIs4pB&>d{y7@WL?YB_!>6!wX?v z>bT#4|6`04Fa07q<*t~BnIO5JN{{UOw`s?*FM8fZ+v%il@e>gCw+Q%uleMpR(ubWG zX=j&2>^z)y!o+`A+6*M*60_yQI_H4QpIIyHk1N?de=+ITYW?KK;^*s!tN1g&9{NaJ z&Lzz?CNzGtzb38P)3sL3z3nzT{t{z9Tx+#zKkNpqR?~zDB@eOj7hr)J*baYd% z&F|%tsK7SVv*cNsN`%JTS*k%LKRFoN5ez9AYsU}8ZI;2%<*4z0K*hvqD}ry!-xue3 z{5}av8c}VzP)>sNi2es!@j zV$M|NZmom)M~oxo?Hny{S({fEIc0&f=lgq3z*5i-TzRC_;+;^0hLjCabKePu<&m-* ze+{;9UZ5?NUu?mD}*e|*uLG4<+2cmtMfKR0%J|GL zL{WpS;tPT}oEAn9KH=vwu=auw%vl}=VB%#?-+_nps$D&Ty9kGUCU4FB18?XY5w5C^HsfDg=O;Yb5C5f^(YssA|TY16BSzLOpmu2 zZ-Xp6XN779hA2|%S)q>UtKL%R=$2@ORpFU?>W=obE1_)9Dp=3uAUGXl-|Yy z6{dRK=?q&wPGM$07r^WKF`5G=v3z*x#82?0TlRI25b>>@cjU;TOm(k_7rT5I5VjEa zb=cP=*c?gG2NqkZewUv*a9nCr_nh6d&*?Siz$apVC{p+C&^lq7C#>*pHxdV6@+$(;_I5sxM8sf~`1bp3=oa#%wne5J93%Z($-mY(yB4VI(&qIkBBqm8 zvZ+sh+O)v1{>e56+vd0q!{@&OH+#B7=k4pT;(W>%a)~f!Z2e_2#yV9HgLa8sFDXo@ ziH3RHg|=*7C;tnKsf$~haA!+dw~7UQah0qYTZrmW8%b5ow9L`Wp-ct+%_ah&fVtD9 z2%4qYH#I~erqk*)g(8xasWz z#-wLAdph`QM?h;)?cA}a7tgMAcDfvKS(f()8@Ipq!jFfE67a!YN+plbC&u9pl*R3T z1T?tV4k%MB(XfedfPubOE88l5!#!k;_2~fP($FJ*2w71~Vok?j@1;qX!WYG4bNs|z zkh$8pAEkMa67|skU=YfbI5wx>sW7XwY=bFD-tn_$H0SU(Vj+EPn9=o$6aN zd)6BW%Ol>^_#ycDcM%2-y@Vk|gNe?x-FYKgLl<`vP=WckW(2*Xj*vgNs7Dw}^b$rD z4PbNPx)WiUrCj@}@d?fIcm>V$pU(XZQv8#$UWqt@ZB^v^jlL;s--5U0+Ub3N=k8?e zPAbIpa{9h)LOGql`1Ay2bAMaI`18`|cg}dV@kZml#z$X%hByCP9v=@DB<3QbyT-Sw zT0lXbC~wZ3C~`743v7Z7`!N0|!$r9dPF})OGCbMgQt*!yne#AIv`~t4=+7{njIZQZ-_g@#JH3TC=OSDYlLs&& zM8Q>G)xrFC>g8KW4^v4TDf;N)S_)EPb4&ZE`rP`=!ND^NCw~f$mL4pBILiBrm!3H| zxLlox%arud3Ffp)^ynn$*o8lAi4k@1(&D*Cj-llR*ELH7oyNhTd_f-fW5!u%q2FVC zFSgF{Xp4=`3Do6vkl|c?f}ulc1$nGF-7$!*0B9J^rYctht?}v6qx2pZ{1_P$4rl|b z;9@HdYJMJ#AN3En$g&C{C9=Dr`{51ci=3 ziPs3V4?68fph7cqZ^4!^zFy&1&KWt*7F-s%f*=vYk8x$PH*x+ZW-5NrfftsXoIcI} zHx`FI$Q}OeI7!IY=q94v3wG0Ob1s}F;l^>}Mr2UK*(A)_N63%7@MBIVu(eYd9eVZ- zqj_@e|HJQ-jtgXeit+3NObGcvL3_mSauNOvf%6I3>_t-A0tSUnZ33Km%b+v1pe>#)A0Uk^5hqXz2^Q zyE)tJ1>$M$+3-})x>LaOVEs|yUF4@>2RziX=JA#rpi^AHxw|ANLr}{2x3gqtQNlvq|0S(+~4<>s@ln9%|W?48!D5RSp)Yr>#{siN93v(g1@K}*qG7p)n z-T_LwkgPGAt0ei(A~Uz%`B-UsG&-7b+w*k5VZWX05D4-F{ODps5w@||LnTh3iqQ^# zch4Y8cMoF{b)4d8csju-1Vv6LamPkk=55Ab17*Gv3ulU0tgi$M=Me5jtD?g~3x{!# z=@%X8I6@p2i%+P7wNP!xUMOD5g;vV%5$WXbuta(20hXVK)Z5e z5X5fUOaAA2o=tL1L!n5_&I>}e-o%}pz{()eVIi~WP|e|=KT4r? z`TeMbQ2r#S`1e}@<4=M~@s|7F@>9xj1IKG4#Pt0*2vS7k6PKtAtOsCBc~Y>(lMlRQ z-}N1hNJAIOvikBRIZ_BNbRmd;SS-ZtFJFL9l@F)$zS7iRV?1|VcMC@|CbWP~GR~9v zu2jwLW|m7M!fj7}5hF~$C_U(c5p^v;q}uqtiH5&-nGnaiQ-OlUo?wpaz!J1Fb*JT! zM{Xs=h7A*zF`TOQ2{a;j~grm8~0{!5Bl1wm{&A(?AQ zVH0iq2-9airi)Szd!#gfQGtT96lxTh!(wwq6~aupCMa-l5u7UZMHnZI7YS*hp^LzG z1h1kGhZ!csrIlcOK+;NwI@h|wH#t9g z0eAHU!X2f3cvd>^Q#sW46UIL_K8=3;B8v!v&=3N@SksvGoq{8OqxcjkWy`e+2|%O4 z%VD{;i>BEb9j`XkDIR<1HZRwZrSimf5$^zFIl8_RwCA)jmup&BeOiyq&|SQXS{3L{ z`qrxOg=$OthXQy>OmgM6l?bjtiw)srDT^Xx^hV|!sklf$pfInDj@rnG zOE~?i4qkJ;GNA3Qd}aqP_)d$&pbGMJQ%QCLiS%SlYL*azT=etRbdJWog*AY(O@n}s zcem&Cx0y37n52G$bhIdB9M2kD?Zv#}Le%p#`mk}QUQ8if7pi}50TVjCOAJ=i)*K9y^} zRFQ62g)~i}2Nxd@zu%c+_HI=6eGSxvK7vN^s-9WD>a}`lVrOQ_X!-|3Vp3{t3FI?f zZiMI+0o&h-(j`o4V&a$aa!jSa>YZd->y{O2)tx>nqw8P~%Q&<_=K>L4_dDnOy_9SsT24_=0@I z8GEv3LeDfc8zwgc<(RcMCwdoSmSYK%nc4ebfzA_XFwFcO+XCy)$765gJpCXJ;~&Zp zBxr-tn3=xL(l@7^n*NO#!}thSk8y|PNF0M$ ztsC58$JspZ_N&?tJ$!lZ^LUb8GmYrxMq}qN%=Cpa$P_#43-dN;yafMK^vA+5Fi9uV zgG-m5X&f9JT)uqt9PP86!INhB^q|q$xb)IxI0=sy80%lt80!PDE^e(jHy82K7x6TI ztDyBOVc3UP;jmABbz2;Qsoy3lFm?HiD1Nsw!{>Is0KYD-3#Wcv0CwX_+<@c8o@Oh! zjxMgSQ-V&048ohFNTi$<`GfEVl{$JI4gCQMmIk%QnU$)&+O;}PR@B|l!jr6G8M=?VA>6u^JYH+h4;)B;Ob3_q zF{Nqz3B3Pp#$DHY|B6rdN|0Lpdlkg32DY6k+;`Qx-ars#-rUBw*{c(YoIxk8;&%gg zo^V$2=eSjzc+$Fik2oi@2?X9md%>*G6#KgjoV>vFgKM=vy}kbEw1*NC^k#d~Zyj$okI!<{8(I6p zUhnFvxe*3jP|8d&+dz6sGq9kkdjY{AhFMT65}(YF-q@@;K}f;gzu4b@>u(G}IfnzH zv(h>~-E8_uZ%m{9bk0iyGR@TtghquIsEK9rg^k7a(Mu@*UqX39UeYWm)wW*y?Ggk+ zx)T1*RhWy#vpnM)M$6d8x!{@3wk}7wLdDscAW=h)Oi@4YQ0>UvqQ!VWEj9YtUg^O- zOv-ISVAHqW%rH)rSq&2scH zWb^TX94C>1XkIsKZnnW_PJycD<&niFAB?ZDSMwIgGP=2le@0Ayapb?%0VVUXQOBJ9 zzQhPo%ff&$n|r?Jav0bd7mZ%8A-J&l(rC0qPuhWPOTN*^Jhc7>7$c?#Y}%xXPuB61 zuEQ9?UT-=~#c56H;0?ReZ#!%TW+?Se+;GC9Hpubd%&lhv@`Vs|M8?;%@P;tkpwL?* z_M4vp#b?J9H%PUA!wLJviu3(Av2;CLG#)b^2g~ryudFt%Za$f|w~sU*%oQ9hv>${y zP&4%{R?dTr^?iP>Plza3| zb9`jqNOk>Tv{6#JCKhT+9j&pVZpSIMA??FhXfOyw-6Q{htv??383+!_M6=gxq6?o| zCZ}a3K|_YOHg~8MVmo0QOPGkbw9ch%hZfkl`n4!1{?y$*we8|`!FM|~$#p$+k*`Qs z&D(yHfkiAR+sK0bFk9ygOxuWJvO|&u9&BOV4&A z$=_^_C%Hv`%FcnB@OYs;fYdr9Vpsq|y585xOl31Ezig4OWPOvDp`V{_H=2Hdd z6|+1O{`PGL@x3Ro2TJ-C#t>cyT?mXQN3!4Hj)ACX`Wq*jqq0*n&|CmLTs^a2WPm_gz;{*s|(O3l{jm_|b;{yNn3RUpEiN?&R zD_h#gYFRTuGjToSgaVZ!0Q($1%?k8VRWHtLm;p2aQdA<^3CP7M^yG7NG*Q%r(zaWaqibPR)#BE4tBSpx2s`G?{vp?!^;HLxPDOr{rA&3hy$1v;y8C zpxnY2QZY3Z=txAJ!LN2k5uu3%*M)f=DLm-#aDK)33dxMIal&|LAwvjVJ#BIorc??1 zdX7}M5^A;&s(HlFQdL-iEsyFF$qN`v-vAR62I)1he8!HBU~rz_XaU)=A?B-vj|HLq72 ztntLoJQ%ew`Vz)}k=dBKZE`2`eFlP#x$bHYx{KL@wzce|JDmDM^e_<$TEX!#Lt0}B z??K4g65L`Pnv%sb+BmU)zc=7@C_%(5MOktIpS^bemQK4ve7)=2ndb_TIthg$*FmJx z%tCLcg0C0nrkgkkTZ^HYE`h;D*%HFTkUpyQ6m%6L>P&>_AKzA_Ug}m62@TXj&Vo%j zTmU{OW&3!rS)@Od5Tcb2p-9J;mDP-=68>wo7IGR}zXqc8m%);Mqih$fjubK~ZXk1|s zYg=%jojvEOtnXxhov3oUWcZB5(Nj*yDipY}mUX9RcDv0SzOKVNOQZ95oF8>}myW@A z;vE?6aPkTij<}U7yR`x$fA4KBh(wb^zml$U?MO0i3Y?MHV8R?zkX3%1g=877Y9oLE zX`_x6ivHH#?x45ZYwrYzY08o_!_oQC=={MA%j#c(8N=IurVXl>3mTQ_hM8?QEM!jt z1=oVM;5ebBefrCwa&fCAWZX&S`HUEE^aiZiGR-Q@wsXxv(xrzn4mu_sowb#NY^+{M z#r=X%WDSN1vW6A6n)i0k?DkqYNDGH|`|utYRyw;&nNurjhl(S$qt=hs4rrLyuN{jX zshwZ_=9OT7EY8no#uOtyW>vP^ewoUt`F4i0Mf%0P(pjr{w&^g}artWRkwXSWE81v! z!SbBl5UkCbcTy+|)_3V16J+Eb(jlG?yyiw^eQnNzsKm@ml$gM}^>M*YwaR$fIyt6s zj@Lo6e9(AXQQCP3!(4%9nvLx+dlo+(yuzTwyC~g%Lz(_MIi6cO<%`~3a=ML+K%Lp# zp#*S}AwVbWX0?mJFfz7p?fhDa|BeV8f-)Gza`LbXjtTC3Rk z$DS2?1NCkVLFa<8PJ^q9!FC3R1dUFBfFz5goVlXc4`0 z?Oc#Y3doc4dqES|I8LXGTfydg1R0VM?^q_e#`(r!3k4UV`%O?xl=7i|5V#r?-k15GK zP|+>v3tr#tiqYOih?s{&aSIF#llE;JqXNQ^JM^#SS1O*s(nKsK7zQUqvH9~lJ_W@e zlnHYiAz_?wV{at7yA37-Nt}iSI)-U~U2=L3#_5M!5u=!Ms>v##*Z+kvH1>>}U>tnR zc-r`Y@x#VX8lN^^Eap`UzRxbnclMHfG98XljoPFbraPHUrg=J1*r`iY?QJz37SpZO zE=<|R^lp#>8Y`&CSShTC=^jS-BA;Og?vJ8kcytTxM);S{G{8=IXT-4A5zUK#TX5NA zI(+@0nM*KqLT@<}K@h~CWhQ28g@*od1j_*t3(|pO9Jk`KdoP2wS#CS$6=%@26G;_0 zU~L5S7HIrqV}k#zXDv!GW04%IR=$TI^CpZt6tvZ@un4qqi@DG)$mWr)hq~QAr;Th$ zB%+x_F($Bbya8XEWwk)E)InT-e0X?(bLG@eO%s)|a)%h=a0PZK@wo#Uc1~dMg06EG zyU($8cuog;B#1%yXJg3Ue0>u%af=c7>NZG=z5xB)MCwu(9=*7+;%JQhVjinSn#RD` zHqINb#;l4Oj7?nz!>|sL-DF56G1(~twDSTLMzgWtr$mahGCq4e+EYb;>}?U3i*7U& z|J!i(csjzYsDS2xz$0kvKH0NH4>-r8Qq z1XQ>a^uHswxkZR5(ogq)eW4yaT7b8DS%ksvHiW3r#)4J{ zJ_09sp_Ozs*=CZ?;&Hn%w%Rjn*fp#0A1J`nr3wg9k>Ska? zh0_YGcuJ)$qWaCbis?8=d_M{P5)FF{MUY%>*JvhCBNHoSzu%g4>O60}b<8Y-7de*Ac;_nx817 zNySQX7|An#+c|7p+k4~f!{!ARLDjsp&$-A0F9?%#5_sX>nP?{mnw~{6F*>V0f&D-w zuI<)6#=N>~JL#*k6r=cQU@_M~R@JBpVg~vOD3vPeM~)NsL#R1_Xpthxe66%*mRtG~DN|hR*g{DU zbR%w0kTaM*<=}IIkJ>>5&mo&8$STeQ`y_#wTm`B;DXM1 z59@M&EV%7RmE3ew>RMj$B|OVbZ_3g`Q1NueCEb9oY15@Xv*4D;iCjKMO#DbS%QLgR z%=BPwUWJpY3Po9k=$VW9G1h*B@o{+9Y&B2xLt?=m6*dU++iwR;&K8d{ak0^ubE5o} zv8la=Re90~!eoS|IjU?4SFn zAx@#^{^`$#xisI-JdeHIlzDimzE6d`{k!+;w@X24N!R}@lu3Tp?UPTqg7~7 zK?{ljMgO4KZxSg!qC`{YV&aiIggL5EDL+AQ8+Mk550A|22zgy=#u>275xIQ3{FtLH zim4K_aY0K~#9O3E4tAe*xF|U)z}>N1-4)zB>BX}2X(Lt{14%&9zf=^JEexwvy z^F7AH#uLVSjQ6ALs&ozQL@B_3$#_KrI4vUqwN0z@`_j31o5yOP+|rgXinlq5vYg5O%UGB3@_NJRTuDqt9&lj zRi@Sj_mz91*vIHjF?_#kPg96Jt7zI{_o`q-C9ipTurPySuNmYp{OGvQEKI&2GfI)3Ti{8UG#nNDkwKjx{O7`J|NR zP^oD?9Baa)iXyGhYIPjRzZYx*^4+5D1(%`$JK@62jz6-)2;Ieaj`nM`F8Xb4sGXOn zdM_wcTy(qWGZXJs6wKg%b2~!FT?_~56tMUmhH)@ue4X)CBQ+Xen`q{{*>I|n4ktRw zvs_NcNRL*iMv0t_25LB+qZy__b&hF_zP%A>d#|dHcjjmXrP^_SHR0?$3P*#u?aVNS zT8|pgY#(~cNmObP9gS(GGI5@(@IQk)R&>pD5H4W_RD!1*(^u-U0xj7kecNog!4F`# z=0|+5Z92CH&Qo~hJM7@Zie{$k2=2)h{tz)^N+Xjj;G;VlEujSX)iznd%t8@4`zS&E zOZp@JeZ732P+@z2sS{(9%euLFPzkOVK%zyRkOb}MPBc>P3}6hpQ>rSKmy)4zH)tZp zEUWq^DrjS^lVGzdn7*~&VNd6$V77gm%JKlH)K7a0DmoM*v&gr0}Jyw!{ls#lrPQnrWWG(14;5>vKop)CVNm2hd+ z^CHu4Ms^Z(ny4H(jv0!;38963kg5;{SFqYq*}(_{;pi@El`^rw=R0rQX54GM1Ek`| z5T~z}CuORCPpTw>^bN-Y#M+zc985Tt9XU2Cj_vNuDJ$m@9Qnd@%sAIq21H+}r^2xJ z>$}c0vO>PMlOtG6J{S*m>z4u5X@63oix=Z&(oIQm$`IlDBp3zoCkgu_QLGBwSsdo? z_G@t`u6b#lcXkTQ`&}qAJKH#^QK3@W+!>{iO-?YZ~Yx^ z*62Ts>io;_0UeAMTFNlkuX+ML|5e392|gat0HGkntF>$J7vpo+yC26$15^4<{X|8Z zj2*823+_55p<(_5)qE6i4G z1@14UPKo0>N__lVE4#dwkGIX{elcrM0^qlF&l_(E5`FgCF9UeV|aoDE%h6x(cL?hmU7OT@3^n_Ry5>Qf2&3TE=5=~2_4YuJJscuw3$XdD- zb|#uJY{8(}g|CJo1ee@9n#;{xuGDM28s=p{e`gBk7(n0o09r8IjlU~F8CV!Juz6D~ zWR01wtldktO$J6?Az@)&X})^KW?c_0dk zZBnE7y|pb=Tn0C;+F<~7f}99DSF@$9ladt;MhBdh!7o11t`^V}KyQ#o2+}}i|A&$Z ze~qkmYf(3bvC97>d~p(YqifNkp>>JuXT2?zN1bTesn~CcwHkfVz-mmLY8Oj*qr$-!FZr|pyTWsfbvjr zyitPDpF&Wz#>MJ98k1`v%oDOc=Y>m@em@-O}OBw zC``l2tkmQ2b50L^l0|!->nevSLHTYeZ{`Esn}}{eXiQ_o&2d^}+Mc#;OU9&VdT%b9 zqV@un?e5ak=z&T7dO@oM)lnUJk;6N&d;ZWD3ZwmWf9F^S z{*1ZL`12U;H>+%u5~E~x`PEptAR^%(e7|3~3zrXY{s8VSb*cs#87^AUv%;n??0Z#u zSFs*+MgF~7FOGX7T)eAU`z6q8qQ=UbRvMA@6XkALybb#4(1|hqB6b#H#I}rm;}+1| zG%6XosEZU`sYdXXvI(jKayXwhe+HX$G%jd_(*mJnJ^I?|tvJ9y+d&x?`XvClc`*rTxs+w!f5{qlb z;r;S@h=Lk-V>*=Z)vSpRKb|!jH;Q^)^FbFCWeQrwYwxCPt zn4=kz*zWH2c(x6aJypZ8LTroCIi{hlr(4JbyjKJ=F(eg`+bW-18dE*0?FKsTclyL; zyM~EGf%TD^V+yO*9)e!&^O3>#}oNcii;K5A{N2sE;4dffi{Us-6w zyP4(t(&U)c2;v{}uieCw!n7#tL9k_bv@5xYV!<(;nwd@@DO&zqhL%Yc{W!%4OBf3f z;8IW)MmT>3|Ik-j2NjKy@1wNiU|ONm#StJ^jFUzKL!Xcci5|lse~f4Iu&x5n47{Ko z=65j)N_mRtVku8@Kf%cz--(G(mQvFCkb;&5LzD^Q5=|UmfG#hb2=sW)SZqUCT@zti z6v9>FF`ME!!m@p0QY#}`5E6nDdDH`A%C?C9&m|7gq3I-`2uV#qW5hhyS_{;MAiz2c z@LD)PK$WBmzNs46e_)BRY)t3Ted!T-rK+}8W=|E35}VlBLeRat;QDRGy&PF~m!7nv z`i=F-W{&lo%--t>xQR&J8+g; zq`B+_w!a{giLq;(##s%pbSLGE#;oH1-6HC$FvJD7=njrle?2l)8mm%kBG^Z+(nJbb zKE3y*xumSC*!N>qp9|WXW968K{!`OY@elC9fHz7>`zjE;7(9s6!JTr+L+tN~cA0afZwOPE~SV&QE{i8=&QE=-S=~+xHEN%=Sf+*|0((xN?g65Kas! z?~hJU7xUAl$Uby-jE0w&PA$P7CrUR}L;&2^+Cuxp>WyygoT3Mb_BRl*{i zlfXqhe>G)+jpEnPzz7}gXf9xoT&80tK8co2-FRvV6$^{d)tg^)^C~44C>c~7x#-nU zx;)2_pIS{?j~{v1b8silUWd1R9RjS&vMsKa@kqBBw;NCB+2=zBDkT>-hDXS$bi&{6 z6i1ya+3`k&0=8A=b{6frqX#U+?kFqj*Nd?Ge@n%W*eUp!HysaNDgaYHeGwM~hMkp2 zn$`w#S~gq|vPs`LGi}8&Vz(Q@C7jSF+3adE-kUU5A>Br=%Pnr{n7r5pQdcA(F{SWFEHp ze->tAZ>dA(;rAgj5Q4(}F&7^f2p&=p4g0(ew)P^?@V#OW?7x9qa>yDlm1WUbY_GI5 zL)@65I;R6t<;$0k_mmJ}$eF_f+YVkqdF!qSHzV#a9*oC6tNgImLir!~|M3R7rtZ@) zyL&rj;?;0_@Je4SVay8xjDccd9EXhaf4}joHjspGFdF(4dU14Y^H{jRzgJ*gYmW6R z@UF*m$8%Eg9cAg2AlM%(@~#~(w5-rugv3_bW8vIrxy&&Krb8XeFub|$-2v@jOXrqf z)G-=wG#)kHV!RW1saHl?Qyl2{svH9Vp^r`qH^y{V4Kd9s8)L^^$6Yxn6QHt>f8hu8 z^>nzGkH#>b<1XBT9PQ}w$mI+aOE@HF`XKzn!?WVNi5&0h(@7?jzt)IXqQ;t^5!>79 zd4BAB≈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 ~iI^VIX8K2aL&R0sx+C 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 GW;M$vYATK1e^>!uu!c<%KUoV?>*Y{^5mRb|m2 zEC^$uJ$a+s;>r-}Gl$K#2teH6X$DAD1EU{DD%0m;v>y~g3OT4W;z?J)rku%Fy+K+o z8y`2-)Q7E8hwF8bNb2-Eouhw_*#$~%9dKR-UuNgN%YF&~uybrtf3qZr50xVFau3=2 zA&dwjdZ>N-nIGkv8lw0bBM(DLmGO7*LD#8AAD{i)$QwJh&gYzZMSaOzcVDN=(>?%` z>%jV8*>8020Lmw}S2}yNQ)S?x*>S)xx-ekb8wtgo1BI)8%*1WCA4{K*4YL#?|!3(h`fGK z*lb!ZwoVoWI_Om48)P)7b(?)Cq46-=>0mp_SC78axS8;BtK~07ogaUt#cedAeA#(3 zd9a@MZO}pVfyC}RV(lgIjOBiVn`^i^=rXhNFwm5LAy3d6^Guq>CdluVYx0ad7V|O8 zT)25G`I5*K8PFl>c@d%;h?vwHR$8!Hz~a&YEu#&WT1FG3B8tu`74Z2+DDCz{R7}Kk z8D=Hsht?)9B0dUWBf>z)Yz-Kb(F6cITS377?fTc-M!F2!4P7IF-xlYq2!qE+DD4Cr zH7+%>_}9gDrH&V)RD)G1$ymsSIa$HO5SxNxB=CjSIi2J*qO9>WM6$tIdYKASEx91G zu!KQV-^{^nYDRH0*{itW8O?#gnQLYNEXGMjED8t<$J(MWU^HqWIDp`&BwWZEmCRib zz^4C^>wm$1y`EH=jpj6;9!y&3g$_Sx6<7au%)*=|%aJG!W95|r>w&A2$1-xpi;RW4 z3a}WANd=`6Ly{4XNz51(7{>%yj1K;Uot`HGi@1LVw2Ly8?>_RXq*ZxJ1g)Lg`Dxv! zol~_mq4lV=(yK>yOK-$|apbGMjbEkx6ghtQgU>5t8Fr>vAe4skv$4GmMmW%R@SrCE z8yoh<&XyaLgiy@bGh&sWe{fh)6F$03z3gs+zFEBayz0$UlGeVd(vD`2f)!1I#hhuj zWb)2TC(o}IMl;Vhjb@z>G+`YgC7QLH+GVQhR_TSY^wFczPiW0h4)}WrfuWar#x1-xw;)%eDDI^w^aI8&o zn~U3nDM`R$t_svtWqDj>h+^e)=9b;o1xr zSh!x{X@~F%g3N9X#u5?(dGBvf!xrebdr9oFbpdm3GX&-dr5*=yR5K*aJUWlmnxxtX z0nl_>a0*$1C(FZU@g8l0J^bSQ`M!yleDmjhJB95NEv*W((Ai5|$`c(e zjnoogae9+ta(wnS^*!E=^l8=}S3O06Y?`%q#|^q!ZpvPu&@4AzZ&EJ(EJB3L_LJ&i zIB^Enfmzdhb1(Tn`qRU1~Oy)t3igjc35lB^7(A@*z)$&eL0 zLCv59Ni!G96ANZ_!RP979+XyNW#L5&(&|R8=iwz(b!)iiF61>_>6JOP->g zSa0_41i##TYAEU~Mc$oglp!pPU7jM5w18lARaFE<1Nzf#*A`e1W0`~P3**N7^glf# zRW`8hF4A_b%wKk`G(G1kesgrX`n`aC!CTbo@mL-&0p{Fdeah7wWdll&DB5~4vfYWk z!b;DgyUnvRLzhV{0Pej#bAQ^<0HpbG;o>3l&=_{%dlov{Y8eajVR=wqxM(14U@UTF ze#QBw=3Wv%|A+K8>Idkr@3=FMj{`@kN>?f|d-zpW-zjcA3IP#VSdle<(h=TzHw1~Syijjf{!k^n#{9z*5iDLx zg~U3f0{}d*g4M!L&xt`8)6U?gkN&%MBJ1HHsLy)$+%y;&d4{-_9~?y|}ML$l{!k zBD6-7LFY$Pl#PiME0a+-&yC6~2!l0)e)BvuiXy~#9>>&p(Lb>$GkPAvL=*xn+8!(b z%btQ;i_ySTYdPpAxxafavW=A0gGI^7ILyHE-(rs^)ZufxeH|f>r})1XV0JK05XC%0 zsK(sI-oM2vazGln{ky?n(ID7;{|l2Dg?WjAQpl@D@V!AMMRwHI zI=o6IxECKeQC3g}@XG!zCur??ZAxkEg|Vf@{|V|Z7f!KN`;L&doU#eF3FHCw5P0?V zmeg0P+gHzTTQk|I)*$%mDX)8?m5wp((^W9zHACmOu088G$NR#hXGSn7AW77!B_ zAnTRvZkx?Lrx9z?96h=GDD2azXaQFgvF^sUA>K_lPsCLK@XpTXRF#O`YKiZ(E-cT* z;;gPlBC$*h3To$M2``%x-)Y&Az|_?ok8|;bLstC;W0)%4D&&GM(<2(?wGE<_uKyQ@ z@LMBk`1)c$L|{FMum(`>I+dV06>;2)R!vv;O{*%K!`(%K4i0o@h@~`F zgn+npa+BH@Wnoc?g1|zE%ool$76|8IkHMnIK;zQBQPSjT$Rys0@;j7ateCuqX(9q` z^jLENeZ_g(Ce+!5w-F5%;}%3&&7W~FQHv!m9g^r^E`XsCqva{!<})eJ+@#z&`S;=S z?{-gRu!a!@&Z*Os5rid-4Ar!$&ce(#_nhYz>FvcorZ<1%ATx+sQpF?7#SI#DpO_l+ z+XiOJ#D?N2w2`Lj?l7XU3!d^&(VC#C z%m8#&v9{Ya%nE6qO@Y*}P>!reJ!| z6avq1idat2gtC21Nb?k<3K^b_DSme!HF!LRZCK1ag#if!MJ&&TuBgS)L*uK^>CWgH z>1WnyLZ3Eh7DUsvp1O}^U8YX{xK8VttNx>$KvOD!RL{PNV|8f(@MnqT!z+pBsQTfP zX*+e*KSkdZJN*oWb(hkmXJJIQp0WcVWFNmTbtTE9YxLH;8f2m zUobgdDm<_l{PE9oqoq?d`%%9XHmrUvDc+u2kl+2Bfz)Z>1hA!85oz2m>sOXFL*xZ7=rYxZU zb6sO$+F#kq?7z|q8z%^XD*f$TY2Y#sblU?Ox9dpSw&IPt!HBL&7a6R3V}*?-buvZ} zGS^otnm2dILvp2w^yLW*%q@eV6>kRyn{+bq%{PKBdIpW!&FN;P(FHKtxXfV3RUK!&%Lto4}*cEJJ>nHPx6=MHY+0***>S>HsT zh>Jd!FuOz?^ow+RxtjEOpU?Pw-V8ad>{Spy7wbrR(2`{mZDA}sq|q76noY#G^^f$4 z*HxFs&B(nz<9cqoYp#Wki6n}Wf?1qc*!SLapV-u#o^Ijd#OvuzeP4pf<%oH$V%Z8chygNS#&`E^~uFp0)TKQ;jr59rZHUJ|FUiS$YWD5Y3!@DB5!Vm#0 zNXOay3J5h-=7sWjjI9?S*aER2;!0z;#3auXLj|NtqRj#N|Io)e^nld;fFZhzZY!3M zaBNXRNk1ye5oMBBzns%1g%BSrxNY`Ephq3k(el?ByXI0B+5glIxC~L0WLV9qGR4-K z3nvm&jKyf{0o2Du?6W?eJXtx@7dwjqpiZ$UEI|Q_Nt9(Q9J_RI3D?UnDSo+0R0Fp{ zMh+w4?+#c}lV~U&7tsh}uw&fPr32S|a^k7eF-J*NeLXL9Uv|Z)++HFkiTCo;`Fnly z(_LEfvLzB+)fMNUqFaZ%D=Xh-q0iXhy+aNSoc3luoFohE5)XO&z*oq2@Y z{@6koO0%kd6$fo%uFR_JO^{R6&rP3a7JD1A(GX{OfvNIdG=#3cD(hw-SyoRfy~h~Q zz)~zkDjQBJQ z6?39mDbnGP9mwV5leon@Kh**KCf^+=a?0zslS++2qa?T2SCx#;DuW;p*M7Q_TijT$ zUvu7pwq;t!g6lIMz&d<%As_E|h`PkY`-|+F7c{3RRN&;!oIH$5JDCcN%JL`FcKUo- zQJEpD9c|mTn9rOsgN)o3rcF~nH|fHs$CW_ec_O>wcSgw=ZYha%n{z5&*=k_)KzCkG z?T0P39iQU2KmiA_5KN6Z2xbu$h8}SX18F);-Y^_8BW4J5h`nl6z&ZiJC=6j8D(*ns zTXC%SkpY1SYxw%cLq_hW%im7_+%EBN^p-eduFK8nF4>~aWL%VBb_e7%Uy+!Z1*x^a4{H@Py8D+*SARW}^r zCU6mDeY1lriLwC4pQNdhab?xI>aoreihgoD$n0f840Q_-VV)pdxn=qJT_cZp@*cB= zw#YIKW@VWouZbPu`&g~R2N0GxWm*n}2Hc5?-#_iuAaXb|bnPv(W$e(VtiKXwc15^v zK{hvHt}DP2M!;Mh`C)fawQlM1?Mw6W+bpEuW{h5)eh0_9G2A++`sp6?v^ z{tw2_zaf)1e#HR0Sa$8Rljga$xc8Ljx1!--% zdETS8@C^%XxluTDU*m9$A1MogHDK}O$3AZ$hpe9q3(=qraqeb|XV>LLbCE&$xI-AS zLC)P23p!88wCv;YX|k&ey?j2IUOa;SO)}~LvDsY>h`I{ zoEE?^hS`h3qh*H#EsIqrzEQCGHK$OG-F>$?%&z$eG~p8Q!^H-FJE;0 zKmAQ_Q~k4?zNA%EX@6&{U%NlYyq`h7{V~|TM3+8s+^AEv(0IFAOp%Pke@&>y1$zdn zo3)?@!|e8-bv5TKuWb0bUW9+#`L6%?!8i3P)SZuk{x2hwGTDEpmGsF;0u#%X-m6;s zPSTreA4*ruyZ%Yx0CND?9(5P;K~xL!UJ1;aP}UW>;o998A9NQMVKCko3E}4XLJ<>q z-Da8}!ZB~)OM`pFBEgJ_BIn~URupyuZ23mm-9AC!l{}zDC#Y1rATL@*`+8kNvIi7& z6=RX5295uxEv>IHC1k_;VhoEGK!ZS1z#{+*(vhlJO>)mgvb=^_LO_qx_FIS$p{vjn zHx^<$P3Z5^5rkq1fLk{$gG*i*JKbhND76Mt^M#w8<61_u1MI>p%gy#LYxffCIN$Wk zDsg%JZ{_+$SU5>w;2O$%q-Cy=I#b?mL%ko>mU?IWrv;Uy9VGpH?XnKs^Qh)U&9H~b zzkShSsM)=N6X2rY8SlRv7{Q^WPsnPr> zr6g??Bu!S(A2%2u`zZgT$BbH0X;v2(f>z*Rzv}QpCsfIw{I-Bo>0d;Io?NS2Z&ya(|HS@4Ga=Okw6Rvo?Vzn<61oe2_D8V zV-QKRmzu2(E(eU;GqdQ!m$1F=WNCkWP(iqN@F<9ZB?3QD3Vl2fE) zDMbc%7fYlRsyx}K8$dEeh0m`F54#(ZQ+WDmEx|W9P7U#wmNw0N7VNkARkYP}FhFwlACBeENIYPhUumQ{M|{ zp{|OL2DhGO;ly#bE6j0JP6ce|Ja%b~P`G=uaHi;t?%Lh9S5mvD+a8*bI`7RRTRzxw zd0mDA=T4w`bxqtT19#PP#Bl3}>oaJa_i?x)W8LMJ!E)AXq-NOMlEEoiUpLFyTTLTu z1HG#|%tR^et3s2JRuUDl({gTQ?~6B@jiz$XSY+<V2CYHc3f@KPujd-D)u&+DyIS{` z<`##e_(Y&Q|FMpaA7uScJW~Iq#VS~St?xhUhnlx5wC|j?oe|BIY3Z8#HR)-UX7O>` z(wv7c9W*2Nr3{i80i${6^@j^|bA|&VF`2ER+fCkaF!KXy3vr^nT}1A1Tc|tw3|~;)>cgUWPHKS^eeb=nh$DfTqPN%M z2~cv==5)didD}}2RW&jds7B+@2i)aA-F_i^s$@22n7gScRj4n@8}Fd%$2R5p!d_S` zSA})w&Yoy9W#bMUq2xE4i_$3@Z#+1vs}4L0vN zcf{P}eEMAfmo1Yfwahgrhj+h@t1Psn=6-s8_ppKlznpyTX=ju9$hkdcc-k+8ZF1^F zOIzWuQ^OtFUBH>8>A8=PBUIPNrVrq~%5v@Rxu%yE>KJl+Prc8NL0A+@B}A<`yQra9 zxt~%jn<~>G3umtY{W)2_j0|6(5o=OFr!whSum*`FEQ_N(Sa*q{gx$k5r|id*n$>rg zEfs+0`yAM3D@Z`a(I=x9;3#wS@uSq(hb3UM&q>JP)1h>WONYdUCFuR{pB?x(c`fIx zSp_$uE)GUs%WIj;1Ye92%br#}yMUmtmTp=-hD4`9J$FU5h{Xe7(TKeUEMWvUmVluz zzdzHaH7xBZ+&%yR6ChckyaUs+q#cSD_(<(TT$0$?sZ8>@*xp7J2fqKF2{H{#h=Y0QzanFuF6d)93OUBp4EQ-hHj_qk5^I7P2CtGf0IV0DLI}*rl$I$LwC8)Z%xOvlh z^{E=>+*N2O`pdJqBuk1EEMhNX-0mzjjmPtPwD ztWF_0PyE&8`puk|EI3~V>6@jS0=)l%eoon#-K$Ff=uRDlXW^8tC8KsnL@;V2J8Cmp zbQFMw?jfn%6s*MvorCHsc_cY^UH(D2Suczzp zuQL6>%y zLnQ}u5<@S~Nzpl313dUo%3m)PzVuh&LXdnn7L}NUN0|>{=EIzGn~8dhV_b zV#Ik%Btl?{IDAB40SEl#j_e0Ij_XUcTJ;t4g)ndG`(Fki1DXR6p`~Eru@89KDOM6>5%xC&!6ptP@)H3Ea^`=E)5!-;U!! z<~O4^dit>@dvbd9qpl%Wvb_vTV1WxU#U1Zu$_hEy5_w7EcVqpTc6xrmrQeDC4iXE7 zB#NVd7%jVDE&)BwbfyP3DY5Fac5ErcK0HlrC11Unqr~uiE_QtU&fhPBIse1k6Q`DQ z0@Af&&Af+ukC7{;KJ+SSrL+9J^75h?^i3}*Zqngz1avQ2dYE$lUAdMlwQCpu9k|qH zC61ECC^3FYF%Hj*u)RQg&Ww}7)PC>AayTFy z-c@n9(W=KLRdA0EtoiazJB@QoP{+v{mmV{NKXW)`Ejv;~MRGx|oGQAr%t{glgOh{_ zyKpYZ5?wW*Fm7TP_3=U-3`2S$`$z3dY!LS~=Y)QqNhb6$uvOS$8R@a?=FKb$#d4S? zgva`1S{?;SIRpLK*XNS)wKXpF_t?oVCOcGvH8t@69w&sMj8j5V@vfBgmd=1kpALe#e%bS<_TWQba`9<%mTC_^3R6(k{M;Mh-vu*HqSAmEr z5f14Ch=|a*Tu`bYSL{|LxH9+g&j)7+4EY8t6jUEjjPVeT=x6e?kqbLMVtp)8#52oP z%b&&-H%m7Zz;I#GVaP$(+z7A9|M=+Ur%1ksa&H^BZg;2EX^7dreDciMF8m)naskfw z;Lk_aa*@?oZ3Is-DdtZ0MxMuo9(?tNb$sM89X;!3KhB=ykGt_T8@3qcui}!MT)}E~ zv7#nTSEuvmr2w+u{?ys7Z|8<6vGx>#fF-2TzVS9$nHE)G+^|=BLD(x?(5lsj-lT8% zb)Pdd&pLlYI(txW=yJHWvN#La2-_zkJ`EvWU8-FOF#QU~$3-eGlDShIjAAZ7gqhfX zYT2?SSQsKW<+gwL;oggP zvf&<3wu0l88X9vp)~xYo_A@@lh{d65%H(OPA6}~z6SNM+T?e;gQ8XXGI`E+}gb+2b z7ek#87J|y?K^EjiH3L@;sE)dq=*l|xQPt4sz>a+t^>-4IW$VAqpwSqa~)p;(mlm_NRMK#RvA+=BmG zM;%CL0{EVr#R5paTVp`uydN+QCd;=Zqn2?)*I#sPLUJX@h>6M%U2jbEGexd@5(^TK zsQ1lJ8?hMO@x@!ElUunE*P2!M)>#ojvk@51h?%y0AB635izGrD(Gp_abUPgU&lVZB z1d&;0V~7XDpYLE%sAE~>?? zsLk2d-m3e|3RTBnbFhr7Qb*dlYbW#mHW}hROlZquj|Au@w&O7{ql*sQ6)V#wKI9;& z-Oo?1?e;__A9M&9%R}-eFB{H;h$$#S`a2syJJc`<@>>|2LO_{e*1JiDcoy>#_$Wn^ zLg5Pb;kKh2Z}(<=xsnp!MK9}9=FOTlA0Qh4hd(dacF%9UnC)ck$6wdhTISrXn;M7! z1d5UakVB#~Z}nE6(s$jcJS;P^LcTiSQ+bzlJ1Xwt)7B~<0NQ2cz>ABZU1i5l*<1Fi@-I>CoH7+IA!Ad0> zPui0S2q)0!?~%%US!3R!i~iM%g+iz4AS(47@nlZkEq(AGb4Et+LE;CSOWtgj4>qk? z6uCGkggk|wuyqh3hO4MVtkicEC4v208X9``|7R1d3Z&spIYr%A0Nq7>PD%oE$iZb2 zEgge<@DI(NHVIxcbvmKOk88ZchNqYdh&>uJibeT28jhtzGcAxCIJzFP`)%Mx&bO_EVKm@QGl6aTNgnHqA!j* z7g;>CXXLpx%x7Y(Fk_nsJn_;WnI02v@?`$;(i68T`X*XBABC8I7U_3%PGtbJWY`_n zf8c>KC@Jt4Eip)G6V*Tecs39ujOppzo&Lodf8Rz}_b39FE@=H@$ z*5QEBTN^|&ctDJARX8X9+wn62r#bqD`fsAkvk6(dH(6}`2AKZA&!orlHa6Rc&AWKp zBkG^qh~>M9ig3-zMEP+B$p!~vcyHN!ndE@{B_{ZdeCkEZ#Z->Z-|*bReQSCbKDT1} zCgG65t{_11X99++0u+ubcrT2>?F#PD7*eI+EeN*Z#mg|fF2JF63jQjK!(S_St-@h6 z{1M|1tlt7bK|Cm;AH0RZTp-CA$Nb;-PP@8_&x_^!_~OW2;TZ7 zm(U>Y+vojT*%bVD&LPB|N#wx!f4WFSz2e{=zv=bYx4u0G74;{o%nG%vsy8+5#ik;l zTZ7j}7Vzvp!v7};MZ%>2AIo$F@b{l!WG6qww{ewrDsxYiawWej2@GY~w}t!Qv_C#u znvIV4ejm6vzG~|hZNJ}$9>s~>{`9Ax-d=3?2}MtU%CG(ZyQ3R7j*i&|!>FDTc!W-l z?Vybif@s&7pXKi0o;B~j6WS@gha<7%CYGplf4*S^{Ld!sp5znzjg zd@+)$cVEN(9T z5?uNJ5eQ5@cjvl85Ufkj{4oGSw;!mSx-D159}6{F1e{!Z$43(Y)bQ;KpBFPs@fR10 z`BrnMM^AG_@>eZ5f!-j<`7WKGLUyh+93fMJSAnI=+l)^?_2+O_gK>AK&fc78N=jd?^?5b zIpQq3a;7_JfU(5T=hS^PI~6j+3e;bS_&hiwBe3=rum3nej(&cWJF4X8K@v=%#j5^j zIgU6gBY63rIgr+$;t2_b19r8P?7GjVN3PyMCcmL^Ar_N%(9>R>YSELoo8!7}2ivEr zWjdBvidt!qzbR*{kJf~^tg-bzjsH{+u8)}U@mnQ|eH{`?AcE$7>h|ev*l3{{Bae1#m$uq$y{~D3ITljAsI?W!?B5dQ7~(~QR;w9NuWtpx+Qg; z#b@WKtsM`Aj``?fp(jhX;^>lu!E-_WsemJ!pzQIE%@#S%ZU@{XmK66Et@@2JT1yaOQxNmZ&EBBixn0A7*b{94V&q zDjn9^*B)C)Dh6v(YpSf7VdYYC9o8JKQuyyI|Ln7LwPLt5skBtg2!k0C+ zhea!l!mt4Iu4RqvBWRVo>8f?Mv}~DcSLX6%)m6)vAD%)SQ=ifdY2KdUKn`E&h;Q1g zq1$xk_nW#-8JIcv)O{m?kK=)5%4M%9j_jL?Gjj~5x>WUv}YZUA&Bp22fn7uf15^O5>^h5o! zm4qggw5Snv%korU5M-;#it?6|C@z~9SeH?S`#{u+DPRRQ?LMgGg=J-1X$*Z3~(Z2xnb5;{8{L-Nw!InqXY!a0o7c{393<&>33L zANi!-rk{=qSm2*In@&NXv5`#9G?0pdm0#8mH|ZXHQUP!M_kcuq$nKiI@K3WS#WYQ4>*#J4K8;_RFjGpSoonp<@oiGpg1E2%Iy zbP~51b0OQUI^~r~xtW1+{(LQf{ z$_UEJ8l}qX_8RwsvhhJ1bFf>r7o1+}#4sJD%)(f+798UEDtC%=MHzRGKZ*>Qs>A%I z&6&dPc2`|r|E--%h zmJ^<@?hx=)T)5){521T7+B#kC)8UYUNhmDQ5`c1}upB682zx$|8DXEyWTPAz9|1jl;?Vib{yPWDpy^GXL!R3dq?c5WPPnnnyGX;LrGo5xyn@Q|i z!o6-h%SU8$4j#u8JZ5rOZ$x}<&db%D5-r!+%JLl?E&wD6=>ZU}%&g!0 zaC!7WT?AW8mBD9u?jN5#et%Ks)B}F+XFYFNf?_*PvYt<)I0Qo%Jzd!9+~LWbil=G7@Kls@V&} zJThc`tYs23!O%Ymi@Su2No?v6Ugg3*<~mm1h2i9havtwhbwr)%t;>j2{hl&#%Kb(5 z;;^*)#L{0tG!A!$iXlFq;oUqsL z^d~CV411-?gEkG@&IRjlH$7mF6rrX{yWX4~)Za$xE1S%lD#7fx1t*`$JB0~v&b3i^ zCQjMv?13G);1KW~0efAq%-lC;)$l{Sb&+)%&U$4I!^{B=4k}S>I)id>vxa+M9Nxc> zX2qdQtRd13!_2~fZUV$Pz+EOuZ~4~J)L`JgI9{4wwgoy|Vk+xyk__RE;;X4{%zwc@ ze(bSNvEn&X9|vz`QswnpaU(2p^iu-ypI$e9PimOU>yPU20|EYNQUHjI* zyxAvDbY25Ek2c-SVrE3T2tj7p#6q9eU=~0SyU)_}T3i%nBD|X^{}2MuR)FZv<^a7| zRAu)fd4@WR$0Yu2Fn3Si5RDsr7 z&~9ms8RO1Ctlxuj7tD0ucSrtvp6N5*OHbK(XHinsA?a16#lGa1IlnBK{jrQ^y@2^b zPCmc2MzK}dz8Xh;jAbMz&(}2$JZ2*)OvLh6LP}!>4^t#+f}jN{;uN!=4T?_EuX((| zOhCL$kr_$WXGk@hTFHQCEQl|J?q;mT@Y2|_Qp226saJp~pNCtsojSeaoW}C!8L5JU1uBcGP}P%_J?v7Yya&!l ze41SF*PIKvcT+8??^@;Pw2N#b+hOhyp~eOU7Bk_hD?RgYn#j-&y=TK?XbO^kf40$v zf~Ye=sjgV}sDQ_$V-Mt2I{W#~LlsnJ-Dq7Is!hTuTZP3Mkh?PQOr=ma`Q?wb_A(7g zytBRm@r0r;_ZcWdu080tLx>ugHeZD?PNfTLn$(b64Du>)cc-G^pUym-0W}t~-EOaY zJwg#qW(DI^hY45SCyX`Eia@?>(a;<(TRSwQ^~FoZV~~F`C6N1<)s(NRHwg}op3RFs zeVu~`p8A%t5H3>n8$DY+y8faIW+G_CQIYi9uF8u(dG*Xs{Gs64pB|I^8b2*7?3H(A zbr{kc52PQEjfdphlU}8RNnqix?EYvuDxkCeJmRdt#siH;%OR#(N7La_-7lBkiJ~y3 zokFJxp85s}dMD@YuXBRM+O!~%VTXHvl1Kg@l`JJ0a2~X{und%ure^`4(dMa?RS>V{ zp==tU-J4Q2F_2z?J0MbFgrOZj8qqNpg6*Xo^rxj}vcUWdecHJNl$O9f=2QQN<}u$B z)-Sdy(zI!yAJ%RB;VXsVuR8?d-4ka=4i4`4#ilYOyDP67siwG?jK+~3OPBQVgT?<~ z=@ZvHCmITi(Kav)+RzN6si|mKY9^7E2S1j&stn?DYs8I9SE$6i@fwiIIo^V5>jv0b zZqD^0sCS&X+zNvkeU2=#bvr`}XB<@lJ1OA}hUl>*nfhKxC8WB8hT}0Qry`tCB?R3$ z2$r(r$7hy3yHGnL{yV=w|-ed?ixessg=FM1T$=BuN=<+SAW**~MvLAi)T1a`{z882{tA+X07kds1 z9zB%t5@cu^?&4z{nLZxqL*zzuK+%V9MqgcEy* zH;iOwzr5k4y@$14oyYme0)f}5^Bbol6;s(0uzRFSy9kh;$9ufKibiX`7EG7`wE33C zfX~}=!b9@ZUH(RCOnX&(bM4*aH|tCx5kR@*J@tmomUrkv2#6um9UoI=<=HULh#ks8 zm}RmUI9J(G0|tOd)jnIwGZT*Ya$-2`X;iEBorwoiIV0Z*8pe$$Jk~ z5Du@=r#;a#vf<^m7LW9t(E4<4U`7blW$F>IMtpZI8qDW32$MJO7EH6!XIbwXGg+9> z00--S<4hy?t{i|TTvGc+ClPLK8e#c~m4q?VNGQ2~^%`k1h6(4!cF8rCCm4-F-jj6} zu$kmxPQ&#Nklp7FoPCY=*R%SR9b+dncz^%?U_L-@XcHPjZsnAz`;_~pPN~erLi9a% zoT*>D?#`ENufA%Fc7;B0IuF7=W%bgk;#kC8LwC?J3i(~N) z3M3qeI0g%FNGF&0*)o*Po0W}UL!2eNb>yTJ${mJSA~|* zQQvzL{N^d8#eSdI@v^pgwC{ym_as)k%jf=n3A~fcf;sM4W^M-C@i?7p5>&RSDQ2lD z5c7&IBmZ0JewS#DcjFYk6*t6=K5%fn0c-tMo+Iqrx8;*v4^PfZ+l%k)@vVWr_}+@9 zjJZZfR{gx~)U^p0%?Gws-6!0ey`(Jv%gLK7Vs}k#es4#eyf}Z8*XCb}WFyqOSIep~Yp@XW(#Bzs6w!;iM z+l{(4Q(G;<18fI7PyT7LM=M8;7^gx5Kr?&tY1YLNmOF8cKE%Jx%D-;h7hjSFV~Uph ztEG<7XQ46y7Ujk~io z3awuC+(vPTU4T}*n^LV0S%$<_P$M=ULCLit%>hl=A2>C5AQk?u*OY@FeIHLTzGIia zt1}ih1=^(AU4bN*Hi?jdMVDn8^i~W;qyY)6Yd<{uw64?>+@%*`-&%@$+1wFghSsYO@U2v@SNuuRSq^glyFUjDuZ_-kqQv}^X4 z8nmzE2KeXs0n0Y%Zg-vgZfF~hzuxJ{`yX@Wafydl4H!{PxaV?)=Dpc{`8wk>%BHK| ze{#AeecpL|X80-$_jWO%^oK%%_@>-vCvCN-J@6H^jem0OyseX-73Xpl=r*)siqN2# z-#cH?rtd5y{@I*GU||=H@$}UHRR9;BiT!GZkx9NWbwASG1E7f$jt93~zFbM7rky9V zCpP3eMKpWZ)gAD*Q1GtfS*RRMCK{I?FV8QAK;1G# zM8UoHG7b)z7eGz`GrJsY4}d{}xZjHD#U`<~+y*Xt`hH?{`)cBT3v-O>p-wYZQ!_5i zy1LDJfbTIKo#LyrE`Z=|A2*Lo0P5>9dk*l5D#Ir3l!)@eF!y@ksQM>fgOy>J z382pah?eTT#8%ufwo!4x5dl4DpJpxxd!hTpn;taGQ|@%-(cYY&6gPb@*qrf9A{ke~ zGus~hQ^Ajb0U~htYaZ)|=kgNtJ!le&a(3)=>=L@yg@+{Bp;~p%bmLcxpC)3vWFp{basgQMkO2*1yD2Di9>-2)Q z5+Oc&Ns19UMl`;DS<2+x!G`y2}h|hf1^*b_0@|sU&K5z53YEvy9nK@!6YD6(F^A7;;)#`rKyv=t@-V;A% zGP~d-gx5^`h!|wX;&ztR%(ee2m@v(_`6Xu{uZXm;ZWV_GpQ>kuM0@L5R#ikOab6Ym zqQh+^6vsE*d;a8;H5*!5h|!Aj7NdfGw1!$DsZkfC(k=0SDUQ=l)lRGQqj)6FQN#-u zqbyes+}RX^tPSI6-?f4(_75iihnL84N9xlNgARE_c~_nfdiQ0dO> zt(`~takXB3n{OW4CO0yvMBCJIa6wEfdoVp${iBNdxB%dkI zTS}W8_=Iz{Be$E}0$AgmHOLW?eVtHV0#&k%l?br9egHzC`A&I06z{W{{qRIxOT_*e zJzcsp-p@E(gh3eReg5|JH>E!O41G826Er}>FGb(5b=s}Jim@kb|0~Vee@%#gm!d18 z|LH8ozl*v3qx5ZmPx^2EjPSp}&1xb7>2PG-$6X*oUo?98lMRrtz5=5H)S&7Kfd@00 zTh~$`=xNTi>+xs-%(v32;KUF{tAFM&3c7G3cnK0fuw`+gLWF%MY6wmVa`QPS0xhOa zG!WcQy^N;q}g2A0{*VDx<_$tKx)JUq% z{w3$e^SGttv<=2xr!F4huunE5raNKe_!|}8J@pW-z5HRO)tX;%N?4oI;0N;Gg!;dy z_wt`MLJ53ItZeKYoLt;IynOru2>M4AzK{?kMKdhN3!)?|s-_#JWjn6t2VoQ^X_gmd zRX1(d592g1>$V@P0U!h;D25Xx1%MEYpcqcvv)>raupBRllC1o*8D5BW!?bM2_52`= z;v~)TqO9ts?fPMy=4IXXiiMLPNIU5%bVBuzN3g@Mv|tBZK?03qB;T%B zp*`OUbq{I4h`Bkd}>=x@>NcFD7yRKvnMv z3X6->^VB$D(A9=M=XDb|7dMENGmF(oL$@_pE)^f+gk>8GboQRoJDzALkjx|xrK9Nw zAzmqx31d+lAIUtLf%RuJNflSpa@XjmU0DruSqzCPObjwfuc%F?r$3-U(S66{UxB72 zg5p`jwAk0W6hulM%X-*IT71dAU?)L9^|cW%3Z#TtekjnbcqYxIV@ed`)EZP9)s!>P zUHhH1s^x_N2rES`2gH+_gR2B$Ikks_uQpqUubYo6GWxk_ zjF^>Rs>j%VV=av({Gq23Xr*L{$lz`{r6=ubXnw#XAFwncAH|!%l*Eld+qJB#%y#kx z9sVE`*RuX}y|zMbJ9{cC45#{~Wuy%lv?aR3EnL>1c2gO5PQI<`j?`t1RgX*TAH2-0 z-sU*5ROgHcXp?a*33kL~`BBis5GxWR8R;`)@}(kcB>$DZ2#T|E^wP@*E0~lNEXFSl zCrikH-r~VtxvZtyz;$dIJ;`2Mklw^aT}175Nt;NuC+mXtyq>2oA~B0S-1KlhavWEU zL^*-NB_OwLnoPqV65?{~+9=K)B|8zvwXhc(n)4q@ki2JYr4^$(Axh=JSA9FKZjg>i zuOz?{Ln5MO;|0*75fvg9c{%b>S@9C7`7yg*6;Bh%x#`f&aBaIEz&aaGolyEW><&v$9Fd(wQa47Zsq=AoqaJqF% zvQ2ZoQ7XBCcBmUpMc+F~)nbrZ4_)~%6Qvv%RA1m!s^McErlvqch~yV^ic#_*t)sZp z3H|eWnOM#ddGgKv7n&zK;k9*<0|HLp^*iRQ;z6JeN`YG^~Zn){F6*hC#8cRf`>CrJlUuZoYcyy%(IpQv{5$l zN2E^c@ofxrhty%XO*uA_vr&)TfR_leymj*Jj#+}tI#(Tol%K3IItmfwJ5PpeCG33v z%-OqEMbyYMxjbiP9e}h1nD_NONG- z{^Ky6BMGBz(3TxS<7$UNt!0chrO%O^!4Wj16*`hHf5emyg{o5QJo?N*$QevD4=lkR zgGk!TCL<->$Ts0)-I~M-sD4oCT!Z%}WkK;aF4(EiTC3zWrAbYWL#k3aYS(5L1EG7B zj-GlsHK~(up_8n`-MS_7Y)`+$lTq#Y;;|E4wU*loclv;&kk;aZE;Ss$oV)3!{)c03zLj@iY1M=-`vd?0GPejU diff --git a/src/types/icons/font.ts b/src/types/icons/font.ts index f16e15bcd..fc0cf13bd 100644 --- a/src/types/icons/font.ts +++ b/src/types/icons/font.ts @@ -18,6 +18,9 @@ export type FontIconName = | 'arrow-right' | 'ask-support' | 'attach' + | 'auction-drop' + | 'auction-filled' + | 'auction-next-round' | 'auction' | 'author-hidden' | 'avatar-archived-chats' diff --git a/src/types/language.d.ts b/src/types/language.d.ts index 20a2e7321..6b1bb309f 100644 --- a/src/types/language.d.ts +++ b/src/types/language.d.ts @@ -1268,6 +1268,7 @@ export interface LangPair { 'GiftInfoDescriptionFreeUpgrade': undefined; 'GiftInfoDescriptionUpgrade2': undefined; 'GiftInfoDescriptionUpgraded': undefined; + 'GiftInfoDescriptionRefunded': undefined; 'GiftInfoFrom': undefined; 'GiftInfoDate': undefined; 'GiftInfoValue': undefined; @@ -1745,6 +1746,8 @@ export interface LangPair { 'StarGiftReasonDropOriginalDetails': undefined; 'GiftAnUpgradeButton': undefined; 'GiftPrepaidUpgradeTransactionTitle': undefined; + 'StarGiftAuctionBidTransaction': undefined; + 'StarGiftAuctionBidRefundedTransaction': undefined; 'ActionStarGiftPrepaidUpgradedYou': undefined; 'UserNoteTitle': undefined; 'UserNoteHint': undefined; @@ -1787,6 +1790,39 @@ export interface LangPair { 'StarGiftPriceDecreaseInfoLink': undefined; 'StarGiftUpgradeCostModalTitle': 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; 'SettingsItemPrivacyOn': undefined; 'SettingsItemPrivacyOff': undefined; @@ -2645,6 +2681,15 @@ export interface LangPairWithVariables { 'ActionStarGiftLimitedRibbon': { 'total': V; }; + 'ActionStarGiftAuctionWon': { + 'cost': V; + }; + 'ActionStarGiftAuctionFor': { + 'peer': V; + }; + 'ActionStarGiftAuctionBought': { + 'cost': V; + }; 'ActionSuggestedPhotoYou': { 'user': V; }; @@ -3120,6 +3165,43 @@ export interface LangPairWithVariables { 'StarGiftPriceDecreaseTimer': { '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': { 'date': V; }; @@ -3527,6 +3609,34 @@ export interface LangPairPluralWithVariables { 'list': 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 RegularLangKeyWithVariables = keyof LangPairWithVariables; diff --git a/src/util/deepLinkParser.ts b/src/util/deepLinkParser.ts index 21fe2efb9..e4c033143 100644 --- a/src/util/deepLinkParser.ts +++ b/src/util/deepLinkParser.ts @@ -10,7 +10,7 @@ import { isUsernameValid } from './entities/username'; export type DeepLinkMethod = 'resolve' | 'login' | 'passport' | 'settings' | 'join' | 'addstickers' | 'addemoji' | 'setlanguage' | 'addtheme' | 'confirmphone' | 'socks' | 'proxy' | 'privatepost' | 'bg' | 'share' | 'msg' | 'msg_url' | 'invoice' | 'addlist' | 'boost' | 'giftcode' | 'message' | 'premium_offer' | 'premium_multigift' | 'stars_topup' - | 'nft' | 'stars' | 'ton'; + | 'nft' | 'stars' | 'ton' | 'stargift_auction'; interface PublicMessageLink { type: 'publicMessageLink'; @@ -104,6 +104,11 @@ interface GiftUniqueLink { slug: string; } +interface GiftAuctionLink { + type: 'giftAuctionLink'; + slug: string; +} + interface StarsModalLink { type: 'stars'; } @@ -131,6 +136,7 @@ type DeepLink = PremiumMultigiftLink | ChatBoostLink | GiftUniqueLink | + GiftAuctionLink | StarsModalLink | TonModalLink | SettingsScreenLink; @@ -269,6 +275,8 @@ function parseTgLink(url: URL) { return buildChatBoostLink({ username: queryParams.domain, id: queryParams.channel }); case 'giftUniqueLink': return buildGiftUniqueLink({ slug: queryParams.slug }); + case 'giftAuctionLink': + return buildGiftAuctionLink({ slug: queryParams.slug }); case 'stars': return { type: 'stars' } satisfies StarsModalLink; case 'ton': @@ -384,6 +392,11 @@ function parseHttpLink(url: URL) { slug, }); } + case 'giftAuctionLink': { + return buildGiftAuctionLink({ + slug: pathParams[1], + }); + } default: break; } @@ -409,6 +422,7 @@ function getHttpDeepLinkType( if (method === 'm') return 'businessChatLink'; if (method === 'boost') return 'chatBoostLink'; if (method === 'nft') return 'giftUniqueLink'; + if (method === 'auction') return 'giftAuctionLink'; if (method === 'c') { if (queryParams.boost !== undefined) return 'chatBoostLink'; return 'privateChannelLink'; @@ -481,6 +495,8 @@ function getTgDeepLinkType( return 'chatBoostLink'; case 'nft': return 'giftUniqueLink'; + case 'stargift_auction': + return 'giftAuctionLink'; case 'stars': return 'stars'; case 'ton': @@ -710,6 +726,21 @@ function buildGiftUniqueLink(params: BuilderParams): BuilderRetu }; } +function buildGiftAuctionLink(params: BuilderParams): BuilderReturnType { + const { + slug, + } = params; + + if (!slug) { + return undefined; + } + + return { + type: 'giftAuctionLink', + slug, + }; +} + function buildSettingsScreen(screenParam: string) { switch (screenParam) { case 'devices': diff --git a/src/util/deeplink.ts b/src/util/deeplink.ts index f53304340..b0db574f5 100644 --- a/src/util/deeplink.ts +++ b/src/util/deeplink.ts @@ -79,6 +79,9 @@ export const processDeepLink = (url: string, linkContext?: LinkContext): boolean case 'giftUniqueLink': actions.openUniqueGiftBySlug({ slug: parsedLink.slug }); return true; + case 'giftAuctionLink': + actions.openGiftAuctionBySlug({ slug: parsedLink.slug }); + return true; case 'settings': if (!parsedLink.screen) { actions.openLeftColumnContent({ contentKey: LeftColumnContent.Settings });