Chat List: Show active auctions (#6641)
This commit is contained in:
parent
31eaf0e5dd
commit
d0ba0c2530
@ -442,7 +442,7 @@ export function buildApiStarGiftAuctionUserState(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function buildApiStarGiftAuctionState(
|
export function buildApiStarGiftAuctionState(
|
||||||
result: GramJs.payments.StarGiftAuctionState,
|
result: GramJs.payments.StarGiftAuctionState | GramJs.StarGiftActiveAuctionState,
|
||||||
): ApiStarGiftAuctionState | undefined {
|
): ApiStarGiftAuctionState | undefined {
|
||||||
const gift = buildApiStarGift(result.gift);
|
const gift = buildApiStarGift(result.gift);
|
||||||
if (gift.type !== 'starGift') return undefined;
|
if (gift.type !== 'starGift') return undefined;
|
||||||
@ -454,7 +454,7 @@ export function buildApiStarGiftAuctionState(
|
|||||||
gift,
|
gift,
|
||||||
state,
|
state,
|
||||||
userState: buildApiStarGiftAuctionUserState(result.userState),
|
userState: buildApiStarGiftAuctionUserState(result.userState),
|
||||||
timeout: result.timeout,
|
timeout: 'timeout' in result ? result.timeout : undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -459,6 +459,20 @@ export async function fetchStarGiftAuctionAcquiredGifts({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function fetchStarGiftActiveAuctions() {
|
||||||
|
const result = await invokeRequest(new GramJs.payments.GetStarGiftActiveAuctions({
|
||||||
|
hash: DEFAULT_PRIMITIVES.BIGINT,
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (!result || result instanceof GramJs.payments.StarGiftActiveAuctionsNotModified) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
auctions: result.auctions.map(buildApiStarGiftAuctionState).filter(Boolean),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function upgradeStarGift({
|
export function upgradeStarGift({
|
||||||
inputSavedGift,
|
inputSavedGift,
|
||||||
shouldKeepOriginalDetails,
|
shouldKeepOriginalDetails,
|
||||||
|
|||||||
@ -387,7 +387,7 @@ export interface ApiStarGiftAuctionState {
|
|||||||
gift: ApiStarGiftRegular;
|
gift: ApiStarGiftRegular;
|
||||||
state: ApiTypeStarGiftAuctionState;
|
state: ApiTypeStarGiftAuctionState;
|
||||||
userState: ApiStarGiftAuctionUserState;
|
userState: ApiStarGiftAuctionUserState;
|
||||||
timeout: number;
|
timeout?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApiStarGiftAuctionAcquiredGift {
|
export interface ApiStarGiftAuctionAcquiredGift {
|
||||||
|
|||||||
@ -2508,6 +2508,11 @@
|
|||||||
"GiftAuctionWonNotification" = "You won {gift} at the auction!";
|
"GiftAuctionWonNotification" = "You won {gift} at the auction!";
|
||||||
"GiftAuctionLearnMoreAboutGifts" = "Learn more about Telegram Gifts >";
|
"GiftAuctionLearnMoreAboutGifts" = "Learn more about Telegram Gifts >";
|
||||||
"GiftAuctionLearnMoreMenuItem" = "Learn More";
|
"GiftAuctionLearnMoreMenuItem" = "Learn More";
|
||||||
|
"GiftAuctionBidPosition" = "Your bid of {amount} is ranked #{position}";
|
||||||
|
"GiftAuctionListRaiseBid" = "Raise";
|
||||||
|
"GiftAuctionListRound" = "Round {current} of {total}";
|
||||||
|
"GiftAuctionActiveTitle" = "Active Auctions";
|
||||||
|
"GiftAuctionNoActive" = "You are not participating in any auctions";
|
||||||
"StarGiftInfoTitle" = "Telegram Gifts";
|
"StarGiftInfoTitle" = "Telegram Gifts";
|
||||||
"StarGiftInfoSubtitle" = "Gifts are collectible items you can trade or showcase on your profile.";
|
"StarGiftInfoSubtitle" = "Gifts are collectible items you can trade or showcase on your profile.";
|
||||||
"StarGiftInfoUniqueTitle" = "Unique";
|
"StarGiftInfoUniqueTitle" = "Unique";
|
||||||
@ -2603,3 +2608,9 @@
|
|||||||
"SettingsDataClearMediaCache" = "Clear Media Cache";
|
"SettingsDataClearMediaCache" = "Clear Media Cache";
|
||||||
"SettingsDataClearMediaCacheDescription" = "Deletes locally cached media for this account";
|
"SettingsDataClearMediaCacheDescription" = "Deletes locally cached media for this account";
|
||||||
"SettingsDataClearMediaDone" = "Media cache cleared";
|
"SettingsDataClearMediaDone" = "Media cache cleared";
|
||||||
|
"ChatListAuctionTitle_one" = "Active Auction";
|
||||||
|
"ChatListAuctionTitle_other" = "{count} Active Auctions";
|
||||||
|
"ChatListAuctionWinning" = "You are winning";
|
||||||
|
"ChatListAuctionOutbid" = "You've been outbid";
|
||||||
|
"ChatListAuctionMixed" = "You are winning in {winCount} and outbid in {outbidCount}";
|
||||||
|
"ChatListAuctionView" = "View";
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
/* eslint-disable @stylistic/max-len */
|
/* eslint-disable @stylistic/max-len */
|
||||||
|
|
||||||
export { default as StarsGiftModal } from '../components/modals/stars/gift/StarsGiftModal';
|
export { default as StarsGiftModal } from '../components/modals/stars/gift/StarsGiftModal';
|
||||||
export { default as StarsGiftingPickerModal } from '../components/main/premium/StarsGiftingPickerModal';
|
export { default as StarsGiftingPickerModal } from '../components/main/premium/StarsGiftingPickerModal';
|
||||||
export { default as StarsBalanceModal } from '../components/modals/stars/StarsBalanceModal';
|
export { default as StarsBalanceModal } from '../components/modals/stars/StarsBalanceModal';
|
||||||
@ -29,3 +28,4 @@ export { default as GiftDescriptionRemoveModal } from '../components/modals/gift
|
|||||||
export { default as GiftOfferAcceptModal } from '../components/modals/gift/offer/GiftOfferAcceptModal';
|
export { default as GiftOfferAcceptModal } from '../components/modals/gift/offer/GiftOfferAcceptModal';
|
||||||
export { default as ChatRefundModal } from '../components/modals/stars/chatRefund/ChatRefundModal';
|
export { default as ChatRefundModal } from '../components/modals/stars/chatRefund/ChatRefundModal';
|
||||||
export { default as PriceConfirmModal } from '../components/modals/priceConfirm/PriceConfirmModal';
|
export { default as PriceConfirmModal } from '../components/modals/priceConfirm/PriceConfirmModal';
|
||||||
|
export { default as ActiveGiftAuctionsModal } from '../components/modals/gift/auction/ActiveGiftAuctionsModal';
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import type { ElementRef, FC } from '../../lib/teact/teact';
|
import type { ElementRef } from '../../lib/teact/teact';
|
||||||
import { memo, useRef, useState } from '../../lib/teact/teact';
|
import { memo, useRef, useState } from '../../lib/teact/teact';
|
||||||
import { getGlobal } from '../../global';
|
import { getGlobal } from '../../global';
|
||||||
|
|
||||||
import type { ObserveFn } from '../../hooks/useIntersectionObserver';
|
import type { ObserveFn } from '../../hooks/useIntersectionObserver';
|
||||||
import { ApiMessageEntityTypes } from '../../api/types';
|
import { ApiMessageEntityTypes, type ApiSticker } from '../../api/types';
|
||||||
|
|
||||||
import { selectIsAlwaysHighPriorityEmoji } from '../../global/selectors';
|
import { selectIsAlwaysHighPriorityEmoji } from '../../global/selectors';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
@ -21,7 +21,6 @@ import blankImg from '../../assets/blank.png';
|
|||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
ref?: ElementRef<HTMLDivElement>;
|
ref?: ElementRef<HTMLDivElement>;
|
||||||
documentId: string;
|
|
||||||
className?: string;
|
className?: string;
|
||||||
style?: string;
|
style?: string;
|
||||||
size?: number;
|
size?: number;
|
||||||
@ -42,13 +41,20 @@ type OwnProps = {
|
|||||||
observeIntersectionForPlaying?: ObserveFn;
|
observeIntersectionForPlaying?: ObserveFn;
|
||||||
onClick?: NoneToVoidFunction;
|
onClick?: NoneToVoidFunction;
|
||||||
onAnimationEnd?: NoneToVoidFunction;
|
onAnimationEnd?: NoneToVoidFunction;
|
||||||
};
|
} & ({
|
||||||
|
documentId: string;
|
||||||
|
sticker?: undefined;
|
||||||
|
} | {
|
||||||
|
sticker: ApiSticker;
|
||||||
|
documentId?: undefined;
|
||||||
|
});
|
||||||
|
|
||||||
const STICKER_SIZE = 20;
|
const STICKER_SIZE = 20;
|
||||||
|
|
||||||
const CustomEmoji: FC<OwnProps> = ({
|
const CustomEmoji = ({
|
||||||
ref,
|
ref,
|
||||||
documentId,
|
documentId,
|
||||||
|
sticker,
|
||||||
className,
|
className,
|
||||||
style,
|
style,
|
||||||
size = STICKER_SIZE,
|
size = STICKER_SIZE,
|
||||||
@ -69,14 +75,15 @@ const CustomEmoji: FC<OwnProps> = ({
|
|||||||
observeIntersectionForPlaying,
|
observeIntersectionForPlaying,
|
||||||
onClick,
|
onClick,
|
||||||
onAnimationEnd,
|
onAnimationEnd,
|
||||||
}) => {
|
}: OwnProps) => {
|
||||||
let containerRef = useRef<HTMLDivElement>();
|
let containerRef = useRef<HTMLDivElement>();
|
||||||
if (ref) {
|
if (ref) {
|
||||||
containerRef = ref;
|
containerRef = ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
// An alternative to `withGlobal` to avoid adding numerous global containers
|
// An alternative to `withGlobal` to avoid adding numerous global containers
|
||||||
const { customEmoji, canPlay } = useCustomEmoji(documentId);
|
const { customEmoji: customEmojiFromDocumentId, canPlay } = useCustomEmoji(documentId);
|
||||||
|
const customEmoji = customEmojiFromDocumentId || sticker;
|
||||||
|
|
||||||
const loopCountRef = useRef(0);
|
const loopCountRef = useRef(0);
|
||||||
const [shouldPlay, setShouldPlay] = useState(true);
|
const [shouldPlay, setShouldPlay] = useState(true);
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import type {
|
import type {
|
||||||
|
ApiAuctionBidLevel,
|
||||||
ApiStarGift,
|
ApiStarGift,
|
||||||
ApiStarGiftAttribute,
|
ApiStarGiftAttribute,
|
||||||
ApiStarGiftAttributeBackdrop,
|
ApiStarGiftAttributeBackdrop,
|
||||||
@ -122,6 +123,19 @@ export function preloadGiftAttributeStickers(attributes: ApiStarGiftAttribute[])
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getBidAuctionPosition(bidAmount: number, bidDate: number, bidLevels: ApiAuctionBidLevel[]) {
|
||||||
|
if (!bidLevels.length) return 1;
|
||||||
|
|
||||||
|
for (const level of bidLevels) {
|
||||||
|
if (level.amount < bidAmount
|
||||||
|
|| (level.amount === bidAmount && level.date >= bidDate)) {
|
||||||
|
return level.pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bidLevels[bidLevels.length - 1].pos + 1;
|
||||||
|
}
|
||||||
|
|
||||||
export function getGiftRarityTitle(
|
export function getGiftRarityTitle(
|
||||||
lang: LangFn,
|
lang: LangFn,
|
||||||
rarity: ApiStarGiftAttributeModel['rarity'],
|
rarity: ApiStarGiftAttributeModel['rarity'],
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import { useSignalEffect } from '../../../../hooks/useSignalEffect';
|
|||||||
import { applyAnimationState, type PaneState } from '../../../middle/hooks/useHeaderPane';
|
import { applyAnimationState, type PaneState } from '../../../middle/hooks/useHeaderPane';
|
||||||
|
|
||||||
import FrozenAccountPane from './FrozenAccountPane';
|
import FrozenAccountPane from './FrozenAccountPane';
|
||||||
|
import GiftAuctionPane from './GiftAuctionPane';
|
||||||
import SuggestionPane from './SuggestionPane';
|
import SuggestionPane from './SuggestionPane';
|
||||||
import UnconfirmedSessionPane from './UnconfirmedSessionPane';
|
import UnconfirmedSessionPane from './UnconfirmedSessionPane';
|
||||||
|
|
||||||
@ -34,6 +35,7 @@ type StateProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const TOP_MARGIN = 0.5 * REM;
|
const TOP_MARGIN = 0.5 * REM;
|
||||||
|
const ITEM_MARGIN = 0.25 * REM;
|
||||||
const BOTTOM_MARGIN = 0.25 * REM;
|
const BOTTOM_MARGIN = 0.25 * REM;
|
||||||
const FALLBACK_PANE_STATE = { height: 0 };
|
const FALLBACK_PANE_STATE = { height: 0 };
|
||||||
|
|
||||||
@ -46,6 +48,7 @@ const ChatListPanes = ({
|
|||||||
}: OwnProps & StateProps) => {
|
}: OwnProps & StateProps) => {
|
||||||
const [getUnconfirmedSessionHeight, setUnconfirmedSessionHeight] = useSignal<PaneState>(FALLBACK_PANE_STATE);
|
const [getUnconfirmedSessionHeight, setUnconfirmedSessionHeight] = useSignal<PaneState>(FALLBACK_PANE_STATE);
|
||||||
const [getFrozenAccountState, setFrozenAccountState] = useSignal<PaneState>(FALLBACK_PANE_STATE);
|
const [getFrozenAccountState, setFrozenAccountState] = useSignal<PaneState>(FALLBACK_PANE_STATE);
|
||||||
|
const [getGiftAuctionState, setGiftAuctionState] = useSignal<PaneState>(FALLBACK_PANE_STATE);
|
||||||
const [getSuggestionState, setSuggestionState] = useSignal<PaneState>(FALLBACK_PANE_STATE);
|
const [getSuggestionState, setSuggestionState] = useSignal<PaneState>(FALLBACK_PANE_STATE);
|
||||||
|
|
||||||
const isFirstRenderRef = useRef(true);
|
const isFirstRenderRef = useRef(true);
|
||||||
@ -72,20 +75,30 @@ const ChatListPanes = ({
|
|||||||
|
|
||||||
const canShowUnconfirmedSession = !isAccountFrozen && unconfirmedSession;
|
const canShowUnconfirmedSession = !isAccountFrozen && unconfirmedSession;
|
||||||
const canShowSuggestions = !isAccountFrozen && !unconfirmedSession && promoData;
|
const canShowSuggestions = !isAccountFrozen && !unconfirmedSession && promoData;
|
||||||
|
const canShowGiftAuctions = !isAccountFrozen;
|
||||||
|
|
||||||
useSignalEffect(() => {
|
useSignalEffect(() => {
|
||||||
const unconfirmedSessionHeight = getUnconfirmedSessionHeight();
|
const unconfirmedSessionHeight = getUnconfirmedSessionHeight();
|
||||||
const frozenAccountHeight = getFrozenAccountState();
|
const frozenAccountHeight = getFrozenAccountState();
|
||||||
|
const giftAuctionHeight = getGiftAuctionState();
|
||||||
const suggestionHeight = getSuggestionState();
|
const suggestionHeight = getSuggestionState();
|
||||||
|
|
||||||
// Keep in sync with the order of the panes in the DOM
|
// Keep in sync with the order of the panes in the DOM
|
||||||
const stateArray = [unconfirmedSessionHeight, frozenAccountHeight, suggestionHeight];
|
const stateArray = [
|
||||||
|
{ height: TOP_MARGIN, isSpacer: true },
|
||||||
|
unconfirmedSessionHeight,
|
||||||
|
frozenAccountHeight,
|
||||||
|
giftAuctionHeight,
|
||||||
|
{ height: giftAuctionHeight.height ? ITEM_MARGIN : 0, isSpacer: true },
|
||||||
|
suggestionHeight,
|
||||||
|
{ height: BOTTOM_MARGIN, isSpacer: true },
|
||||||
|
];
|
||||||
|
|
||||||
const isFirstRender = isFirstRenderRef.current;
|
const isFirstRender = isFirstRenderRef.current;
|
||||||
const panelsHeight = stateArray.reduce((acc, state) => acc + state.height, 0);
|
const totalHeight = stateArray.reduce((acc, state) => acc + state.height, 0);
|
||||||
const totalHeight = panelsHeight ? panelsHeight + BOTTOM_MARGIN : 0;
|
const panelsHeight = totalHeight - TOP_MARGIN - BOTTOM_MARGIN;
|
||||||
|
|
||||||
onHeightChange(totalHeight);
|
onHeightChange(panelsHeight !== 0 ? totalHeight : 0);
|
||||||
|
|
||||||
const leftColumn = document.getElementById('LeftColumn');
|
const leftColumn = document.getElementById('LeftColumn');
|
||||||
if (!leftColumn) return;
|
if (!leftColumn) return;
|
||||||
@ -93,7 +106,6 @@ const ChatListPanes = ({
|
|||||||
applyAnimationState({
|
applyAnimationState({
|
||||||
list: stateArray,
|
list: stateArray,
|
||||||
noTransition: isFirstRender,
|
noTransition: isFirstRender,
|
||||||
topMargin: TOP_MARGIN,
|
|
||||||
zIndexIncrease: true,
|
zIndexIncrease: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -102,7 +114,7 @@ const ChatListPanes = ({
|
|||||||
'--chat-list-panes-height': `${totalHeight}px`,
|
'--chat-list-panes-height': `${totalHeight}px`,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, [getUnconfirmedSessionHeight, getFrozenAccountState, getSuggestionState]);
|
}, [getUnconfirmedSessionHeight, getFrozenAccountState, getSuggestionState, getGiftAuctionState]);
|
||||||
|
|
||||||
if (!shouldRender) return undefined;
|
if (!shouldRender) return undefined;
|
||||||
|
|
||||||
@ -124,6 +136,10 @@ const ChatListPanes = ({
|
|||||||
unconfirmedSession={canShowUnconfirmedSession ? unconfirmedSession : undefined}
|
unconfirmedSession={canShowUnconfirmedSession ? unconfirmedSession : undefined}
|
||||||
onPaneStateChange={setUnconfirmedSessionHeight}
|
onPaneStateChange={setUnconfirmedSessionHeight}
|
||||||
/>
|
/>
|
||||||
|
<GiftAuctionPane
|
||||||
|
canShow={canShowGiftAuctions}
|
||||||
|
onPaneStateChange={setGiftAuctionState}
|
||||||
|
/>
|
||||||
<SuggestionPane
|
<SuggestionPane
|
||||||
promoData={canShowSuggestions ? promoData : undefined}
|
promoData={canShowSuggestions ? promoData : undefined}
|
||||||
onPaneStateChange={setSuggestionState}
|
onPaneStateChange={setSuggestionState}
|
||||||
|
|||||||
30
src/components/left/main/panes/ChatPane.module.scss
Normal file
30
src/components/left/main/panes/ChatPane.module.scss
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
@use "../../../../styles/mixins";
|
||||||
|
|
||||||
|
.pane {
|
||||||
|
@include mixins.chat-list-pane;
|
||||||
|
|
||||||
|
cursor: var(--custom-cursor, pointer);
|
||||||
|
border-radius: var(--border-radius-default);
|
||||||
|
line-height: 1.25;
|
||||||
|
background-color: var(--color-background-secondary);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
--emoji-size: 1.125rem;
|
||||||
|
--custom-emoji-size: var(--emoji-size);
|
||||||
|
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
font-weight: var(--font-weight-semibold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
--emoji-size: 1rem;
|
||||||
|
--custom-emoji-size: var(--emoji-size);
|
||||||
|
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
36
src/components/left/main/panes/GiftAuctionPane.module.scss
Normal file
36
src/components/left/main/panes/GiftAuctionPane.module.scss
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
.root {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
grid-template-rows: auto 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
grid-column: 1 / 2;
|
||||||
|
grid-row: 1 / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.giftEmojis {
|
||||||
|
margin-inline-end: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
grid-column: 1 / 3;
|
||||||
|
grid-row: 2 / 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
grid-column: 2 / 3;
|
||||||
|
grid-row: 1 / 3;
|
||||||
|
place-self: center;
|
||||||
|
|
||||||
|
font-size: 0.875rem !important;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonIcon {
|
||||||
|
font-size: 0.875rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outbid {
|
||||||
|
color: var(--color-error);
|
||||||
|
}
|
||||||
136
src/components/left/main/panes/GiftAuctionPane.tsx
Normal file
136
src/components/left/main/panes/GiftAuctionPane.tsx
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
import { memo, useMemo } from '@teact';
|
||||||
|
import { getActions, withGlobal } from '../../../../global';
|
||||||
|
|
||||||
|
import type { ApiStarGiftAuctionState, ApiStarGiftAuctionStateActive } from '../../../../api/types';
|
||||||
|
import type { GlobalState } from '../../../../global/types';
|
||||||
|
|
||||||
|
import buildClassName from '../../../../util/buildClassName';
|
||||||
|
import { partition } from '../../../../util/iteratees';
|
||||||
|
import { getBidAuctionPosition } from '../../../common/helpers/gifts';
|
||||||
|
|
||||||
|
import useLang from '../../../../hooks/useLang';
|
||||||
|
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||||
|
import useHeaderPane, { type PaneState } from '../../../middle/hooks/useHeaderPane';
|
||||||
|
|
||||||
|
import CustomEmoji from '../../../common/CustomEmoji';
|
||||||
|
import Button from '../../../ui/Button';
|
||||||
|
import TextTimer from '../../../ui/TextTimer';
|
||||||
|
|
||||||
|
import paneStyles from './ChatPane.module.scss';
|
||||||
|
import styles from './GiftAuctionPane.module.scss';
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
canShow?: boolean;
|
||||||
|
onPaneStateChange: (state: PaneState) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
type StateProps = Pick<GlobalState, 'activeGiftAuctionIds' | 'giftAuctionByGiftId'>;
|
||||||
|
|
||||||
|
const GiftAuctionPane = ({
|
||||||
|
canShow,
|
||||||
|
activeGiftAuctionIds,
|
||||||
|
giftAuctionByGiftId,
|
||||||
|
onPaneStateChange,
|
||||||
|
}: OwnProps & StateProps) => {
|
||||||
|
const { openGiftAuctionBidModal, openActiveGiftAuctionsModal } = getActions();
|
||||||
|
const isOpen = canShow && Boolean(activeGiftAuctionIds?.length);
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
|
const { ref, shouldRender } = useHeaderPane({
|
||||||
|
isOpen,
|
||||||
|
onStateChange: onPaneStateChange,
|
||||||
|
withResizeObserver: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const [activeAuctions, winningCount, outbidCount] = useMemo(() => {
|
||||||
|
const auctions = activeGiftAuctionIds?.map((id) => giftAuctionByGiftId?.[id])
|
||||||
|
.filter((auc): auc is ApiStarGiftAuctionState => (
|
||||||
|
auc?.state.type === 'active' && Boolean(auc.userState.bidAmount)),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!auctions) return [undefined, 0, 0];
|
||||||
|
const [winning, outbid] = partition(auctions, (auction) => {
|
||||||
|
const state = auction.state as ApiStarGiftAuctionStateActive;
|
||||||
|
const position = getBidAuctionPosition(
|
||||||
|
auction.userState.bidAmount!, auction.userState.bidDate!, state.bidLevels,
|
||||||
|
);
|
||||||
|
return position <= auction.gift.giftsPerRound!;
|
||||||
|
});
|
||||||
|
return [auctions, winning.length, outbid.length];
|
||||||
|
}, [activeGiftAuctionIds, giftAuctionByGiftId]);
|
||||||
|
const activeAuctionsCount = activeAuctions?.length || 0;
|
||||||
|
const singleActiveAuction = activeAuctions?.length === 1 ? activeAuctions[0] : undefined;
|
||||||
|
|
||||||
|
function renderSubtitleText() {
|
||||||
|
if (!winningCount && !outbidCount) return undefined;
|
||||||
|
if (winningCount && !outbidCount) return lang('ChatListAuctionWinning');
|
||||||
|
if (!winningCount && outbidCount) return lang('ChatListAuctionOutbid');
|
||||||
|
return lang('ChatListAuctionMixed', { winCount: winningCount, outbidCount });
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClick = useLastCallback(() => {
|
||||||
|
if (!activeAuctions?.length) return;
|
||||||
|
if (singleActiveAuction) {
|
||||||
|
openGiftAuctionBidModal({ auctionGiftId: singleActiveAuction.gift.id });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
openActiveGiftAuctionsModal();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!shouldRender) return undefined;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
className={buildClassName(paneStyles.pane, styles.root)}
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
onClick={handleClick}
|
||||||
|
>
|
||||||
|
<div className={buildClassName(paneStyles.title, styles.title)}>
|
||||||
|
<span className={styles.giftEmojis}>
|
||||||
|
{activeAuctions?.map((auction) => (
|
||||||
|
<CustomEmoji
|
||||||
|
key={auction.gift.id}
|
||||||
|
sticker={auction.gift.sticker}
|
||||||
|
loopLimit={1}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</span>
|
||||||
|
{lang('ChatListAuctionTitle', { count: activeAuctionsCount }, { pluralValue: activeAuctionsCount })}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={buildClassName(
|
||||||
|
paneStyles.subtitle, styles.subtitle, !winningCount && outbidCount && styles.outbid,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{renderSubtitleText()}
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
className={styles.button}
|
||||||
|
iconName={singleActiveAuction ? 'auction-filled' : undefined}
|
||||||
|
iconClassName={styles.buttonIcon}
|
||||||
|
size="tiny"
|
||||||
|
pill
|
||||||
|
onClick={handleClick}
|
||||||
|
>
|
||||||
|
{singleActiveAuction ? (
|
||||||
|
<TextTimer
|
||||||
|
endsAt={(singleActiveAuction.state as ApiStarGiftAuctionStateActive).nextRoundAt}
|
||||||
|
shouldShowZeroOnEnd
|
||||||
|
/>
|
||||||
|
) : lang('ChatListAuctionView')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(withGlobal<OwnProps>(
|
||||||
|
(global): Complete<StateProps> => {
|
||||||
|
return {
|
||||||
|
activeGiftAuctionIds: global.activeGiftAuctionIds,
|
||||||
|
giftAuctionByGiftId: global.giftAuctionByGiftId,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
)(GiftAuctionPane));
|
||||||
@ -1,43 +1,17 @@
|
|||||||
@use "../../../../styles/mixins";
|
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
@include mixins.chat-list-pane;
|
|
||||||
|
|
||||||
cursor: var(--custom-cursor, pointer);
|
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr min-content;
|
grid-template-columns: 1fr min-content;
|
||||||
grid-template-rows: min-content 1fr;
|
grid-template-rows: min-content 1fr;
|
||||||
|
|
||||||
border-radius: var(--border-radius-default);
|
|
||||||
|
|
||||||
line-height: 1.25;
|
|
||||||
|
|
||||||
background-color: var(--color-background-secondary);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
opacity: 0.85;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
--emoji-size: 1.125rem;
|
|
||||||
--custom-emoji-size: var(--emoji-size);
|
|
||||||
|
|
||||||
grid-column: 1 / 2;
|
grid-column: 1 / 2;
|
||||||
grid-row: 1 / 2;
|
grid-row: 1 / 2;
|
||||||
font-size: 0.9375rem;
|
|
||||||
font-weight: var(--font-weight-semibold);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtitle {
|
.subtitle {
|
||||||
--emoji-size: 1rem;
|
|
||||||
--custom-emoji-size: var(--emoji-size);
|
|
||||||
|
|
||||||
grid-column: 1 / 3;
|
grid-column: 1 / 3;
|
||||||
grid-row: 2 / 3;
|
grid-row: 2 / 3;
|
||||||
font-size: 0.875rem;
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.closeIcon {
|
.closeIcon {
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { getActions } from '../../../../global';
|
|||||||
import type { ApiPromoData } from '../../../../api/types';
|
import type { ApiPromoData } from '../../../../api/types';
|
||||||
import type { RegularLangKey } from '../../../../types/language';
|
import type { RegularLangKey } from '../../../../types/language';
|
||||||
|
|
||||||
|
import buildClassName from '../../../../util/buildClassName';
|
||||||
import { renderTextWithEntities } from '../../../common/helpers/renderTextWithEntities';
|
import { renderTextWithEntities } from '../../../common/helpers/renderTextWithEntities';
|
||||||
|
|
||||||
import useCurrentOrPrev from '../../../../hooks/useCurrentOrPrev';
|
import useCurrentOrPrev from '../../../../hooks/useCurrentOrPrev';
|
||||||
@ -13,6 +14,7 @@ import useHeaderPane, { type PaneState } from '../../../middle/hooks/useHeaderPa
|
|||||||
|
|
||||||
import Icon from '../../../common/icons/Icon';
|
import Icon from '../../../common/icons/Icon';
|
||||||
|
|
||||||
|
import paneStyles from './ChatPane.module.scss';
|
||||||
import styles from './SuggestionPane.module.scss';
|
import styles from './SuggestionPane.module.scss';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
@ -90,13 +92,13 @@ const SuggestionPane = ({ promoData, onPaneStateChange }: OwnProps) => {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={styles.root}
|
className={buildClassName(paneStyles.pane, styles.root)}
|
||||||
role="button"
|
role="button"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
>
|
>
|
||||||
<div className={styles.title}>{title}</div>
|
<div className={buildClassName(paneStyles.title, styles.title)}>{title}</div>
|
||||||
<div className={styles.subtitle}>{message}</div>
|
<div className={buildClassName(paneStyles.subtitle, styles.subtitle)}>{message}</div>
|
||||||
<Icon name="close" className={styles.closeIcon} onClick={handleDismiss} />
|
<Icon name="close" className={styles.closeIcon} onClick={handleDismiss} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -266,6 +266,7 @@ const Main = ({
|
|||||||
loadContentSettings,
|
loadContentSettings,
|
||||||
loadGiftAuction,
|
loadGiftAuction,
|
||||||
loadPromoData,
|
loadPromoData,
|
||||||
|
loadActiveGiftAuctions,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
if (DEBUG && !DEBUG_isLogged) {
|
if (DEBUG && !DEBUG_isLogged) {
|
||||||
@ -347,6 +348,7 @@ const Main = ({
|
|||||||
loadRestrictedEmojiStickers();
|
loadRestrictedEmojiStickers();
|
||||||
loadQuickReplies();
|
loadQuickReplies();
|
||||||
loadTimezones();
|
loadTimezones();
|
||||||
|
loadActiveGiftAuctions();
|
||||||
}
|
}
|
||||||
}, [isMasterTab, isSynced, isAppConfigLoaded, isAccountFrozen]);
|
}, [isMasterTab, isSynced, isAppConfigLoaded, isAccountFrozen]);
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,7 @@ export interface PaneState {
|
|||||||
element?: HTMLElement;
|
element?: HTMLElement;
|
||||||
height: number;
|
height: number;
|
||||||
isOpen?: boolean;
|
isOpen?: boolean;
|
||||||
|
isSpacer?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Max slide transition duration
|
// Max slide transition duration
|
||||||
@ -130,18 +131,17 @@ export function applyAnimationState({
|
|||||||
list,
|
list,
|
||||||
noTransition = false,
|
noTransition = false,
|
||||||
zIndexIncrease,
|
zIndexIncrease,
|
||||||
topMargin = 0,
|
|
||||||
}: {
|
}: {
|
||||||
list: PaneState[];
|
list: PaneState[];
|
||||||
noTransition?: boolean;
|
noTransition?: boolean;
|
||||||
zIndexIncrease?: boolean;
|
zIndexIncrease?: boolean;
|
||||||
topMargin?: number;
|
|
||||||
}) {
|
}) {
|
||||||
let cumulativeHeight = 0;
|
let cumulativeHeight = 0;
|
||||||
for (let i = 0; i < list.length; i++) {
|
for (let i = 0; i < list.length; i++) {
|
||||||
const state = list[i];
|
const state = list[i];
|
||||||
const element = state.element;
|
const element = state.element;
|
||||||
if (!element) {
|
if (!element) {
|
||||||
|
if (state.isSpacer) cumulativeHeight += state.height;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ export function applyAnimationState({
|
|||||||
|
|
||||||
const apply = () => {
|
const apply = () => {
|
||||||
setExtraStyles(element, {
|
setExtraStyles(element, {
|
||||||
transform: `translateY(${state.isOpen ? shiftPx : `calc(${shiftPx} - ${topMargin}px - 100%)`})`,
|
transform: `translateY(${state.isOpen ? shiftPx : `calc(${shiftPx} - 100%)`})`,
|
||||||
zIndex: String(-i),
|
zIndex: String(-i),
|
||||||
transition: noTransition ? 'none' : '',
|
transition: noTransition ? 'none' : '',
|
||||||
});
|
});
|
||||||
@ -158,7 +158,7 @@ export function applyAnimationState({
|
|||||||
if (!element.dataset.isPanelOpen && state.isOpen && !noTransition) {
|
if (!element.dataset.isPanelOpen && state.isOpen && !noTransition) {
|
||||||
// Start animation right above its final position
|
// Start animation right above its final position
|
||||||
setExtraStyles(element, {
|
setExtraStyles(element, {
|
||||||
transform: `translateY(calc(${shiftPx} - ${topMargin}px - 100%))`,
|
transform: `translateY(calc(${shiftPx} - 100%))`,
|
||||||
zIndex: String(zIndexIncrease ? i : -i),
|
zIndex: String(zIndexIncrease ? i : -i),
|
||||||
transition: 'none',
|
transition: 'none',
|
||||||
});
|
});
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import DeleteAccountModal from './deleteAccount/DeleteAccountModal.async';
|
|||||||
import EmojiStatusAccessModal from './emojiStatusAccess/EmojiStatusAccessModal.async';
|
import EmojiStatusAccessModal from './emojiStatusAccess/EmojiStatusAccessModal.async';
|
||||||
import FrozenAccountModal from './frozenAccount/FrozenAccountModal.async';
|
import FrozenAccountModal from './frozenAccount/FrozenAccountModal.async';
|
||||||
import AboutStarGiftModal from './gift/AboutStarGiftModal.async';
|
import AboutStarGiftModal from './gift/AboutStarGiftModal.async';
|
||||||
|
import ActiveGiftAuctionsModal from './gift/auction/ActiveGiftAuctionsModal.async';
|
||||||
import GiftAuctionAcquiredModal from './gift/auction/GiftAuctionAcquiredModal.async';
|
import GiftAuctionAcquiredModal from './gift/auction/GiftAuctionAcquiredModal.async';
|
||||||
import GiftAuctionBidModal from './gift/auction/GiftAuctionBidModal.async';
|
import GiftAuctionBidModal from './gift/auction/GiftAuctionBidModal.async';
|
||||||
import GiftAuctionChangeRecipientModal from './gift/auction/GiftAuctionChangeRecipientModal.async';
|
import GiftAuctionChangeRecipientModal from './gift/auction/GiftAuctionChangeRecipientModal.async';
|
||||||
@ -107,6 +108,7 @@ type ModalKey = keyof Pick<TabState,
|
|||||||
'giftAuctionInfoModal' |
|
'giftAuctionInfoModal' |
|
||||||
'giftAuctionChangeRecipientModal' |
|
'giftAuctionChangeRecipientModal' |
|
||||||
'giftAuctionAcquiredModal' |
|
'giftAuctionAcquiredModal' |
|
||||||
|
'activeGiftAuctionsModal' |
|
||||||
'starGiftPriceDecreaseInfoModal' |
|
'starGiftPriceDecreaseInfoModal' |
|
||||||
'aboutStarGiftModal' |
|
'aboutStarGiftModal' |
|
||||||
'monetizationVerificationModal' |
|
'monetizationVerificationModal' |
|
||||||
@ -182,6 +184,7 @@ const MODALS: ModalRegistry = {
|
|||||||
giftAuctionInfoModal: GiftAuctionInfoModal,
|
giftAuctionInfoModal: GiftAuctionInfoModal,
|
||||||
giftAuctionChangeRecipientModal: GiftAuctionChangeRecipientModal,
|
giftAuctionChangeRecipientModal: GiftAuctionChangeRecipientModal,
|
||||||
giftAuctionAcquiredModal: GiftAuctionAcquiredModal,
|
giftAuctionAcquiredModal: GiftAuctionAcquiredModal,
|
||||||
|
activeGiftAuctionsModal: ActiveGiftAuctionsModal,
|
||||||
starGiftPriceDecreaseInfoModal: StarGiftPriceDecreaseInfoModal,
|
starGiftPriceDecreaseInfoModal: StarGiftPriceDecreaseInfoModal,
|
||||||
aboutStarGiftModal: AboutStarGiftModal,
|
aboutStarGiftModal: AboutStarGiftModal,
|
||||||
monetizationVerificationModal: VerificationMonetizationModal,
|
monetizationVerificationModal: VerificationMonetizationModal,
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
import type { OwnProps } from './ActiveGiftAuctionsModal';
|
||||||
|
|
||||||
|
import { Bundles } from '../../../../util/moduleLoader';
|
||||||
|
|
||||||
|
import useModuleLoader from '../../../../hooks/useModuleLoader';
|
||||||
|
|
||||||
|
const ActiveGiftAuctionsModalAsync = (props: OwnProps) => {
|
||||||
|
const { modal } = props;
|
||||||
|
const ActiveGiftAuctionsModal = useModuleLoader(Bundles.Stars, 'ActiveGiftAuctionsModal', !modal);
|
||||||
|
|
||||||
|
return ActiveGiftAuctionsModal ? <ActiveGiftAuctionsModal {...props} /> : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ActiveGiftAuctionsModalAsync;
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
.gift {
|
||||||
|
--custom-emoji-size: 2rem;
|
||||||
|
|
||||||
|
margin-inline-end: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timer {
|
||||||
|
margin-inline-start: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.noActive {
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
--border-radius-default: 0;
|
||||||
|
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog {
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
123
src/components/modals/gift/auction/ActiveGiftAuctionsModal.tsx
Normal file
123
src/components/modals/gift/auction/ActiveGiftAuctionsModal.tsx
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
import { memo, useMemo } from '@teact';
|
||||||
|
import { getActions, withGlobal } from '../../../../global';
|
||||||
|
|
||||||
|
import type { ApiStarGiftAuctionState, ApiStarGiftAuctionStateActive } from '../../../../api/types';
|
||||||
|
import type { TabState } from '../../../../global/types';
|
||||||
|
|
||||||
|
import { formatStarsAsIcon } from '../../../../util/localization/format';
|
||||||
|
import { getBidAuctionPosition } from '../../../common/helpers/gifts';
|
||||||
|
import { REM } from '../../../common/helpers/mediaDimensions';
|
||||||
|
|
||||||
|
import useLang from '../../../../hooks/useLang';
|
||||||
|
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||||
|
|
||||||
|
import CustomEmoji from '../../../common/CustomEmoji';
|
||||||
|
import Button from '../../../ui/Button';
|
||||||
|
import ListItem from '../../../ui/ListItem';
|
||||||
|
import Modal from '../../../ui/Modal';
|
||||||
|
import TextTimer from '../../../ui/TextTimer';
|
||||||
|
|
||||||
|
import styles from './ActiveGiftAuctionsModal.module.scss';
|
||||||
|
|
||||||
|
export type OwnProps = {
|
||||||
|
modal: TabState['activeGiftAuctionsModal'];
|
||||||
|
};
|
||||||
|
|
||||||
|
type StateProps = {
|
||||||
|
activeGiftAuctionIds?: string[];
|
||||||
|
giftAuctionByGiftId?: Record<string, ApiStarGiftAuctionState>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ICON_SIZE = 2 * REM;
|
||||||
|
|
||||||
|
const ActiveGiftAuctionsModal = ({
|
||||||
|
modal, activeGiftAuctionIds, giftAuctionByGiftId,
|
||||||
|
}: OwnProps & StateProps) => {
|
||||||
|
const { closeActiveGiftAuctionsModal } = getActions();
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
|
const activeAuctions = useMemo(() => {
|
||||||
|
return activeGiftAuctionIds?.map((id) => giftAuctionByGiftId?.[id])
|
||||||
|
.filter((auc): auc is ApiStarGiftAuctionState => (
|
||||||
|
auc?.state.type === 'active' && Boolean(auc.userState.bidAmount)
|
||||||
|
));
|
||||||
|
}, [activeGiftAuctionIds, giftAuctionByGiftId]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isOpen={Boolean(modal)}
|
||||||
|
onClose={closeActiveGiftAuctionsModal}
|
||||||
|
hasCloseButton
|
||||||
|
isCondensedHeader
|
||||||
|
title={lang('GiftAuctionActiveTitle')}
|
||||||
|
dialogClassName={styles.dialog}
|
||||||
|
contentClassName={styles.content}
|
||||||
|
>
|
||||||
|
{activeAuctions?.length
|
||||||
|
? activeAuctions.map((auction) => <ActiveAuctionItem key={auction.gift.id} auction={auction} />)
|
||||||
|
: <div className={styles.noActive}>{lang('GiftAuctionNoActive')}</div>}
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
function ActiveAuctionItem({ auction }: { auction: ApiStarGiftAuctionState }) {
|
||||||
|
const lang = useLang();
|
||||||
|
const { openGiftAuctionBidModal, closeActiveGiftAuctionsModal } = getActions();
|
||||||
|
|
||||||
|
const { userState, gift } = auction;
|
||||||
|
const state = auction.state as ApiStarGiftAuctionStateActive;
|
||||||
|
|
||||||
|
const bidPosition = useMemo(() => {
|
||||||
|
return getBidAuctionPosition(userState.bidAmount!, userState.bidDate!, state.bidLevels);
|
||||||
|
}, [userState, state.bidLevels]);
|
||||||
|
|
||||||
|
const handleClick = useLastCallback(() => {
|
||||||
|
openGiftAuctionBidModal({ auctionGiftId: gift.id });
|
||||||
|
closeActiveGiftAuctionsModal();
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ListItem
|
||||||
|
leftElement={<CustomEmoji className={styles.gift} sticker={gift.sticker} size={ICON_SIZE} loopLimit={1} />}
|
||||||
|
rightElement={(
|
||||||
|
<Button
|
||||||
|
size="tiny"
|
||||||
|
pill
|
||||||
|
fluid
|
||||||
|
iconName="auction-filled"
|
||||||
|
onClick={handleClick}
|
||||||
|
>
|
||||||
|
{lang('GiftAuctionListRaiseBid')}
|
||||||
|
<TextTimer className={styles.timer} endsAt={state.nextRoundAt} shouldShowZeroOnEnd />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
multiline
|
||||||
|
onClick={handleClick}
|
||||||
|
>
|
||||||
|
<div className="title">
|
||||||
|
{lang('GiftAuctionListRound', {
|
||||||
|
current: lang.number(state.currentRound),
|
||||||
|
total: lang.number(state.totalRounds),
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div className="subtitle">
|
||||||
|
{lang('GiftAuctionBidPosition', {
|
||||||
|
amount: formatStarsAsIcon(lang, userState.bidAmount!, { noStyles: true }),
|
||||||
|
position: lang.number(bidPosition),
|
||||||
|
}, {
|
||||||
|
withNodes: true,
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</ListItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(withGlobal<OwnProps>(
|
||||||
|
(global): Complete<StateProps> => {
|
||||||
|
const { activeGiftAuctionIds, giftAuctionByGiftId } = global;
|
||||||
|
return {
|
||||||
|
activeGiftAuctionIds,
|
||||||
|
giftAuctionByGiftId,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
)(ActiveGiftAuctionsModal));
|
||||||
@ -10,6 +10,7 @@ import type { TabState } from '../../../../global/types';
|
|||||||
|
|
||||||
import { selectPeer, selectTabState } from '../../../../global/selectors';
|
import { selectPeer, selectTabState } from '../../../../global/selectors';
|
||||||
import { formatStarsAsIcon } from '../../../../util/localization/format';
|
import { formatStarsAsIcon } from '../../../../util/localization/format';
|
||||||
|
import { getBidAuctionPosition } from '../../../common/helpers/gifts';
|
||||||
import renderText from '../../../common/helpers/renderText';
|
import renderText from '../../../common/helpers/renderText';
|
||||||
|
|
||||||
import { useTransitionActiveKey } from '../../../../hooks/animations/useTransitionActiveKey';
|
import { useTransitionActiveKey } from '../../../../hooks/animations/useTransitionActiveKey';
|
||||||
@ -191,14 +192,7 @@ const GiftAuctionBidModal = ({
|
|||||||
const { bidLevels } = activeState;
|
const { bidLevels } = activeState;
|
||||||
const userBidDate = userState?.bidDate || Number.MAX_SAFE_INTEGER;
|
const userBidDate = userState?.bidDate || Number.MAX_SAFE_INTEGER;
|
||||||
|
|
||||||
for (const level of bidLevels) {
|
return getBidAuctionPosition(selectedBidAmount, userBidDate, 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]);
|
}, [selectedBidAmount, activeState, userState?.bidDate]);
|
||||||
|
|
||||||
function renderInfoCards() {
|
function renderInfoCards() {
|
||||||
|
|||||||
@ -112,7 +112,6 @@ const GiftTransferModal = ({
|
|||||||
hasCloseButton
|
hasCloseButton
|
||||||
shouldAdaptToSearch
|
shouldAdaptToSearch
|
||||||
withFixedHeight
|
withFixedHeight
|
||||||
ignoreFreeze
|
|
||||||
>
|
>
|
||||||
<PeerPicker<Categories>
|
<PeerPicker<Categories>
|
||||||
itemIds={displayIds}
|
itemIds={displayIds}
|
||||||
|
|||||||
@ -370,8 +370,8 @@
|
|||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
|
|
||||||
&.round {
|
&.round {
|
||||||
width: 1.875rem;
|
width: 1.75rem;
|
||||||
height: 1.875rem;
|
height: 1.75rem;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,8 +380,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.pill {
|
&.pill {
|
||||||
height: 1.875rem;
|
height: 1.75rem;
|
||||||
padding: 0.3125rem 1rem;
|
padding: 0.25rem 0.5rem;
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,7 +45,6 @@ export type OwnProps = {
|
|||||||
dialogRef?: ElementRef<HTMLDivElement>;
|
dialogRef?: ElementRef<HTMLDivElement>;
|
||||||
isLowStackPriority?: boolean;
|
isLowStackPriority?: boolean;
|
||||||
dialogContent?: React.ReactNode;
|
dialogContent?: React.ReactNode;
|
||||||
ignoreFreeze?: boolean;
|
|
||||||
moreMenuItems?: TeactNode;
|
moreMenuItems?: TeactNode;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onCloseAnimationEnd?: () => void;
|
onCloseAnimationEnd?: () => void;
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import useForceUpdate from '../../hooks/useForceUpdate';
|
|||||||
import AnimatedCounter from '../common/AnimatedCounter';
|
import AnimatedCounter from '../common/AnimatedCounter';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
|
className?: string;
|
||||||
endsAt: number;
|
endsAt: number;
|
||||||
shouldShowZeroOnEnd?: boolean;
|
shouldShowZeroOnEnd?: boolean;
|
||||||
onEnd?: NoneToVoidFunction;
|
onEnd?: NoneToVoidFunction;
|
||||||
@ -16,7 +17,7 @@ type OwnProps = {
|
|||||||
|
|
||||||
const UPDATE_FREQUENCY = 500; // Sometimes second gets skipped if using 1000
|
const UPDATE_FREQUENCY = 500; // Sometimes second gets skipped if using 1000
|
||||||
|
|
||||||
const TextTimer = ({ endsAt, shouldShowZeroOnEnd, onEnd }: OwnProps) => {
|
const TextTimer = ({ className, endsAt, shouldShowZeroOnEnd, onEnd }: OwnProps) => {
|
||||||
const forceUpdate = useForceUpdate();
|
const forceUpdate = useForceUpdate();
|
||||||
|
|
||||||
const serverTime = getServerTime();
|
const serverTime = getServerTime();
|
||||||
@ -35,8 +36,8 @@ const TextTimer = ({ endsAt, shouldShowZeroOnEnd, onEnd }: OwnProps) => {
|
|||||||
const time = formatMediaDuration(timeLeft);
|
const time = formatMediaDuration(timeLeft);
|
||||||
|
|
||||||
const timeParts = time.split(':');
|
const timeParts = time.split(':');
|
||||||
const timeCounter = (
|
return (
|
||||||
<span style="font-variant-numeric: tabular-nums;">
|
<span className={className} style="font-variant-numeric: tabular-nums;">
|
||||||
{timeParts.map((part, index) => (
|
{timeParts.map((part, index) => (
|
||||||
<>
|
<>
|
||||||
{index > 0 && ':'}
|
{index > 0 && ':'}
|
||||||
@ -45,12 +46,6 @@ const TextTimer = ({ endsAt, shouldShowZeroOnEnd, onEnd }: OwnProps) => {
|
|||||||
))}
|
))}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
{timeCounter}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TextTimer;
|
export default TextTimer;
|
||||||
|
|||||||
@ -612,6 +612,7 @@ addActionHandler('loadGiftAuction', async (global, _actions, payload): Promise<v
|
|||||||
|
|
||||||
global = getGlobal();
|
global = getGlobal();
|
||||||
global = replaceGiftAuction(global, auctionState);
|
global = replaceGiftAuction(global, auctionState);
|
||||||
|
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -735,3 +736,19 @@ addActionHandler('declineStarGiftOffer', async (global, actions, payload): Promi
|
|||||||
shouldDecline: true,
|
shouldDecline: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addActionHandler('loadActiveGiftAuctions', async (global, actions, payload): Promise<void> => {
|
||||||
|
const result = await callApi('fetchStarGiftActiveAuctions');
|
||||||
|
|
||||||
|
if (!result) return;
|
||||||
|
|
||||||
|
global = getGlobal();
|
||||||
|
result.auctions.forEach((auction) => {
|
||||||
|
global = replaceGiftAuction(global, auction);
|
||||||
|
});
|
||||||
|
global = {
|
||||||
|
...global,
|
||||||
|
activeGiftAuctionIds: result.auctions.map((auction) => auction.gift.id),
|
||||||
|
};
|
||||||
|
setGlobal(global);
|
||||||
|
});
|
||||||
|
|||||||
@ -260,6 +260,11 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
|||||||
case 'updateStarGiftAuctionUserState': {
|
case 'updateStarGiftAuctionUserState': {
|
||||||
const { giftId, userState } = update;
|
const { giftId, userState } = update;
|
||||||
|
|
||||||
|
if (!global.giftAuctionByGiftId?.[giftId]) {
|
||||||
|
actions.loadActiveGiftAuctions();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
global = updateGiftAuctionUserState(global, giftId, userState);
|
global = updateGiftAuctionUserState(global, giftId, userState);
|
||||||
|
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
|
|||||||
@ -676,3 +676,13 @@ addActionHandler('resetSelectedGiftCollection', (global, actions, payload): Acti
|
|||||||
peerId, shouldRefresh: true, tabId: tabState.id,
|
peerId, shouldRefresh: true, tabId: tabState.id,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addActionHandler('openActiveGiftAuctionsModal', (global, actions, payload): ActionReturnType => {
|
||||||
|
const { tabId = getCurrentTabId() } = payload || {};
|
||||||
|
|
||||||
|
return updateTabState(global, {
|
||||||
|
activeGiftAuctionsModal: true,
|
||||||
|
}, tabId);
|
||||||
|
});
|
||||||
|
|
||||||
|
addTabStateResetterAction('closeActiveGiftAuctionsModal', 'activeGiftAuctionsModal');
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import type {
|
|||||||
import type { GlobalState } from '../types';
|
import type { GlobalState } from '../types';
|
||||||
|
|
||||||
import { getCurrentTabId } from '../../util/establishMultitabRole';
|
import { getCurrentTabId } from '../../util/establishMultitabRole';
|
||||||
import { omit } from '../../util/iteratees';
|
import { omit, unique } from '../../util/iteratees';
|
||||||
import { updateTabState } from './tabs';
|
import { updateTabState } from './tabs';
|
||||||
|
|
||||||
export function removeGiftInfoOriginalDetails<T extends GlobalState>(
|
export function removeGiftInfoOriginalDetails<T extends GlobalState>(
|
||||||
@ -74,7 +74,11 @@ export function updateGiftAuction<T extends GlobalState>(
|
|||||||
...global,
|
...global,
|
||||||
giftAuctionByGiftId: {
|
giftAuctionByGiftId: {
|
||||||
...global.giftAuctionByGiftId,
|
...global.giftAuctionByGiftId,
|
||||||
[giftId]: auctionState,
|
[giftId]: {
|
||||||
|
...auctionState,
|
||||||
|
// Keep timeout in case of updates from active auction list, as those do not have this field
|
||||||
|
timeout: auctionState.timeout || currentAuction.timeout,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -123,6 +127,21 @@ export function updateGiftAuctionUserState<T extends GlobalState>(
|
|||||||
return global;
|
return global;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentBidDate = giftAuction.userState.bidDate;
|
||||||
|
if (userState.bidDate !== currentBidDate) {
|
||||||
|
if (userState.bidDate) {
|
||||||
|
global = {
|
||||||
|
...global,
|
||||||
|
activeGiftAuctionIds: unique([...(global.activeGiftAuctionIds || []), giftId]),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
global = {
|
||||||
|
...global,
|
||||||
|
activeGiftAuctionIds: global.activeGiftAuctionIds?.filter((id) => id !== giftId),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...global,
|
...global,
|
||||||
giftAuctionByGiftId: {
|
giftAuctionByGiftId: {
|
||||||
@ -140,11 +159,32 @@ export function replaceGiftAuction<T extends GlobalState>(
|
|||||||
auctionState: ApiStarGiftAuctionState,
|
auctionState: ApiStarGiftAuctionState,
|
||||||
): T {
|
): T {
|
||||||
const giftId = auctionState.gift.id;
|
const giftId = auctionState.gift.id;
|
||||||
|
|
||||||
|
const previousAuction = global.giftAuctionByGiftId?.[giftId];
|
||||||
|
if (previousAuction) {
|
||||||
|
if (previousAuction.userState.bidDate !== auctionState.userState.bidDate) {
|
||||||
|
if (auctionState.userState.bidDate) {
|
||||||
|
global = {
|
||||||
|
...global,
|
||||||
|
activeGiftAuctionIds: unique([...(global.activeGiftAuctionIds || []), giftId]),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
global = {
|
||||||
|
...global,
|
||||||
|
activeGiftAuctionIds: global.activeGiftAuctionIds?.filter((id) => id !== giftId),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...global,
|
...global,
|
||||||
giftAuctionByGiftId: {
|
giftAuctionByGiftId: {
|
||||||
...global.giftAuctionByGiftId,
|
...global.giftAuctionByGiftId,
|
||||||
[giftId]: auctionState,
|
[giftId]: {
|
||||||
|
...auctionState,
|
||||||
|
timeout: auctionState.timeout || previousAuction?.timeout,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -158,9 +198,11 @@ export function removeGiftAuction<T extends GlobalState>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const rest = omit(global.giftAuctionByGiftId, [giftId]);
|
const rest = omit(global.giftAuctionByGiftId, [giftId]);
|
||||||
|
const activeGiftAuctionIds = global.activeGiftAuctionIds?.filter((id) => id !== giftId);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...global,
|
...global,
|
||||||
giftAuctionByGiftId: Object.keys(rest).length ? rest : undefined,
|
giftAuctionByGiftId: Object.keys(rest).length ? rest : undefined,
|
||||||
|
activeGiftAuctionIds,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2714,6 +2714,9 @@ export interface ActionPayloads {
|
|||||||
gift: ApiStarGiftUnique;
|
gift: ApiStarGiftUnique;
|
||||||
} & WithTabId;
|
} & WithTabId;
|
||||||
closeGiftInfoValueModal: WithTabId | undefined;
|
closeGiftInfoValueModal: WithTabId | undefined;
|
||||||
|
loadActiveGiftAuctions: undefined;
|
||||||
|
openActiveGiftAuctionsModal: WithTabId | undefined;
|
||||||
|
closeActiveGiftAuctionsModal: WithTabId | undefined;
|
||||||
openGiftAuctionModal: {
|
openGiftAuctionModal: {
|
||||||
gift: ApiStarGiftRegular;
|
gift: ApiStarGiftRegular;
|
||||||
} & WithTabId;
|
} & WithTabId;
|
||||||
|
|||||||
@ -331,6 +331,7 @@ export type GlobalState = {
|
|||||||
starGiftCollections?: {
|
starGiftCollections?: {
|
||||||
byPeerId: Record<string, ApiStarGiftCollection[]>;
|
byPeerId: Record<string, ApiStarGiftCollection[]>;
|
||||||
};
|
};
|
||||||
|
activeGiftAuctionIds?: string[];
|
||||||
giftAuctionByGiftId?: Record<string, ApiStarGiftAuctionState>;
|
giftAuctionByGiftId?: Record<string, ApiStarGiftAuctionState>;
|
||||||
|
|
||||||
stickers: {
|
stickers: {
|
||||||
|
|||||||
@ -937,6 +937,8 @@ export type TabState = {
|
|||||||
acquiredGifts?: ApiStarGiftAuctionAcquiredGift[];
|
acquiredGifts?: ApiStarGiftAuctionAcquiredGift[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
activeGiftAuctionsModal?: true;
|
||||||
|
|
||||||
starGiftPriceDecreaseInfoModal?: {
|
starGiftPriceDecreaseInfoModal?: {
|
||||||
prices: ApiStarGiftUpgradePrice[];
|
prices: ApiStarGiftUpgradePrice[];
|
||||||
currentPrice: number;
|
currentPrice: number;
|
||||||
|
|||||||
@ -1895,6 +1895,7 @@ payments.getUniqueStarGiftValueInfo#4365af6b slug:string = payments.UniqueStarGi
|
|||||||
payments.checkCanSendGift#c0c4edc9 gift_id:long = payments.CheckCanSendGiftResult;
|
payments.checkCanSendGift#c0c4edc9 gift_id:long = payments.CheckCanSendGiftResult;
|
||||||
payments.getStarGiftAuctionState#5c9ff4d6 auction:InputStarGiftAuction version:int = payments.StarGiftAuctionState;
|
payments.getStarGiftAuctionState#5c9ff4d6 auction:InputStarGiftAuction version:int = payments.StarGiftAuctionState;
|
||||||
payments.getStarGiftAuctionAcquiredGifts#6ba2cbec gift_id:long = payments.StarGiftAuctionAcquiredGifts;
|
payments.getStarGiftAuctionAcquiredGifts#6ba2cbec gift_id:long = payments.StarGiftAuctionAcquiredGifts;
|
||||||
|
payments.getStarGiftActiveAuctions#a5d0514d hash:long = payments.StarGiftActiveAuctions;
|
||||||
payments.resolveStarGiftOffer#e9ce781c flags:# decline:flags.0?true offer_msg_id:int = Updates;
|
payments.resolveStarGiftOffer#e9ce781c flags:# decline:flags.0?true offer_msg_id:int = Updates;
|
||||||
phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
|
phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
|
||||||
phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
|
phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
|
||||||
|
|||||||
@ -355,6 +355,7 @@
|
|||||||
"payments.getStarGiftCollections",
|
"payments.getStarGiftCollections",
|
||||||
"payments.getStarGiftAuctionState",
|
"payments.getStarGiftAuctionState",
|
||||||
"payments.getStarGiftAuctionAcquiredGifts",
|
"payments.getStarGiftAuctionAcquiredGifts",
|
||||||
|
"payments.getStarGiftActiveAuctions",
|
||||||
"payments.resolveStarGiftOffer",
|
"payments.resolveStarGiftOffer",
|
||||||
"langpack.getLangPack",
|
"langpack.getLangPack",
|
||||||
"langpack.getStrings",
|
"langpack.getStrings",
|
||||||
|
|||||||
21
src/types/language.d.ts
vendored
21
src/types/language.d.ts
vendored
@ -1844,6 +1844,9 @@ export interface LangPair {
|
|||||||
'GiftAuctionTapToBidMore': undefined;
|
'GiftAuctionTapToBidMore': undefined;
|
||||||
'GiftAuctionLearnMoreAboutGifts': undefined;
|
'GiftAuctionLearnMoreAboutGifts': undefined;
|
||||||
'GiftAuctionLearnMoreMenuItem': undefined;
|
'GiftAuctionLearnMoreMenuItem': undefined;
|
||||||
|
'GiftAuctionListRaiseBid': undefined;
|
||||||
|
'GiftAuctionActiveTitle': undefined;
|
||||||
|
'GiftAuctionNoActive': undefined;
|
||||||
'StarGiftInfoTitle': undefined;
|
'StarGiftInfoTitle': undefined;
|
||||||
'StarGiftInfoSubtitle': undefined;
|
'StarGiftInfoSubtitle': undefined;
|
||||||
'StarGiftInfoUniqueTitle': undefined;
|
'StarGiftInfoUniqueTitle': undefined;
|
||||||
@ -1913,6 +1916,9 @@ export interface LangPair {
|
|||||||
'SettingsDataClearMediaCache': undefined;
|
'SettingsDataClearMediaCache': undefined;
|
||||||
'SettingsDataClearMediaCacheDescription': undefined;
|
'SettingsDataClearMediaCacheDescription': undefined;
|
||||||
'SettingsDataClearMediaDone': undefined;
|
'SettingsDataClearMediaDone': undefined;
|
||||||
|
'ChatListAuctionWinning': undefined;
|
||||||
|
'ChatListAuctionOutbid': undefined;
|
||||||
|
'ChatListAuctionView': undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LangPairWithVariables<V = LangVariable> {
|
export interface LangPairWithVariables<V = LangVariable> {
|
||||||
@ -3312,6 +3318,14 @@ export interface LangPairWithVariables<V = LangVariable> {
|
|||||||
'GiftAuctionWonNotification': {
|
'GiftAuctionWonNotification': {
|
||||||
'gift': V;
|
'gift': V;
|
||||||
};
|
};
|
||||||
|
'GiftAuctionBidPosition': {
|
||||||
|
'amount': V;
|
||||||
|
'position': V;
|
||||||
|
};
|
||||||
|
'GiftAuctionListRound': {
|
||||||
|
'current': V;
|
||||||
|
'total': V;
|
||||||
|
};
|
||||||
'SettingsPasskeyUsedAt': {
|
'SettingsPasskeyUsedAt': {
|
||||||
'date': V;
|
'date': V;
|
||||||
};
|
};
|
||||||
@ -3346,6 +3360,10 @@ export interface LangPairWithVariables<V = LangVariable> {
|
|||||||
'status': V;
|
'status': V;
|
||||||
'onlineCount': V;
|
'onlineCount': V;
|
||||||
};
|
};
|
||||||
|
'ChatListAuctionMixed': {
|
||||||
|
'winCount': V;
|
||||||
|
'outbidCount': V;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LangPairPlural {
|
export interface LangPairPlural {
|
||||||
@ -3785,6 +3803,9 @@ export interface LangPairPluralWithVariables<V = LangVariable> {
|
|||||||
'AttachmentSendFile': {
|
'AttachmentSendFile': {
|
||||||
'count': V;
|
'count': V;
|
||||||
};
|
};
|
||||||
|
'ChatListAuctionTitle': {
|
||||||
|
'count': V;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
export type RegularLangKey = keyof LangPair;
|
export type RegularLangKey = keyof LangPair;
|
||||||
export type RegularLangKeyWithVariables = keyof LangPairWithVariables;
|
export type RegularLangKeyWithVariables = keyof LangPairWithVariables;
|
||||||
|
|||||||
@ -49,11 +49,15 @@ export function formatTonAsIcon(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function formatStarsAsIcon(lang: LangFn, amount: number | string, options?: {
|
export function formatStarsAsIcon(lang: LangFn, amount: number | string, options?: {
|
||||||
asFont?: boolean; className?: string; containerClassName?: string; }) {
|
asFont?: boolean;
|
||||||
const { asFont, className, containerClassName } = options || {};
|
className?: string;
|
||||||
|
containerClassName?: string;
|
||||||
|
noStyles?: boolean;
|
||||||
|
}) {
|
||||||
|
const { asFont, className, containerClassName, noStyles } = options || {};
|
||||||
const icon = asFont
|
const icon = asFont
|
||||||
? <Icon name="star" className={buildClassName('star-amount-icon', className)} />
|
? <Icon name="star" className={buildClassName(!noStyles && 'star-amount-icon', className)} />
|
||||||
: <StarIcon type="gold" className={buildClassName('star-amount-icon', className)} size="adaptive" />;
|
: <StarIcon type="gold" className={buildClassName(!noStyles && 'star-amount-icon', className)} size="adaptive" />;
|
||||||
|
|
||||||
if (containerClassName) {
|
if (containerClassName) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user