623 lines
19 KiB
TypeScript
623 lines
19 KiB
TypeScript
import type { FC } from '@teact';
|
|
import {
|
|
memo, useEffect, useMemo, useRef, useState,
|
|
} from '@teact';
|
|
import type React from '../../../lib/teact/teact';
|
|
import { getActions, withGlobal } from '../../../global';
|
|
|
|
import type {
|
|
ApiDisallowedGifts,
|
|
ApiPeer,
|
|
ApiPremiumGiftCodeOption,
|
|
ApiSavedStarGift,
|
|
ApiStarGift,
|
|
ApiStarGiftRegular,
|
|
ApiStarsAmount,
|
|
} from '../../../api/types';
|
|
import type { TabState } from '../../../global/types';
|
|
import type { StarGiftCategory } from '../../../types';
|
|
|
|
import { STARS_CURRENCY_CODE } from '../../../config';
|
|
import { getUserFullName } from '../../../global/helpers';
|
|
import { getPeerTitle, isApiPeerChat, isApiPeerUser } from '../../../global/helpers/peers';
|
|
import { selectTabState } from '../../../global/selectors';
|
|
import { selectPeer, selectUserFullInfo } from '../../../global/selectors';
|
|
import buildClassName from '../../../util/buildClassName';
|
|
import { throttle } from '../../../util/schedulers';
|
|
|
|
import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';
|
|
import { useIntersectionObserver } from '../../../hooks/useIntersectionObserver';
|
|
import useLang from '../../../hooks/useLang';
|
|
import useLastCallback from '../../../hooks/useLastCallback';
|
|
import useOldLang from '../../../hooks/useOldLang';
|
|
|
|
import Avatar from '../../common/Avatar';
|
|
import InteractiveSparkles from '../../common/InteractiveSparkles';
|
|
import SafeLink from '../../common/SafeLink';
|
|
import Button from '../../ui/Button';
|
|
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 GiftItemPremium from './GiftItemPremium';
|
|
import GiftItemStar from './GiftItemStar';
|
|
import GiftModalResaleScreen from './GiftModalResaleScreen';
|
|
import GiftResaleFilters from './GiftResaleFilters';
|
|
import StarGiftCategoryList from './StarGiftCategoryList';
|
|
|
|
import styles from './GiftModal.module.scss';
|
|
|
|
export type OwnProps = {
|
|
modal: TabState['giftModal'];
|
|
};
|
|
|
|
export type GiftOption = ApiPremiumGiftCodeOption | ApiStarGift;
|
|
|
|
type StateProps = {
|
|
boostPerSentGift?: number;
|
|
starGiftsById?: Record<string, ApiStarGiftRegular>;
|
|
starGiftIdsByCategory?: Record<StarGiftCategory, string[]>;
|
|
myCollectibleGiftsById?: Record<string, ApiSavedStarGift>;
|
|
myCollectibleGiftIds?: string[];
|
|
starBalance?: ApiStarsAmount;
|
|
peer?: ApiPeer;
|
|
isSelf?: boolean;
|
|
disallowedGifts?: ApiDisallowedGifts;
|
|
resaleGiftsCount?: number;
|
|
areResaleGiftsLoading?: boolean;
|
|
selectedResaleGift?: ApiStarGift;
|
|
tabId: number;
|
|
};
|
|
|
|
const AVATAR_SIZE = 100;
|
|
const INTERSECTION_THROTTLE = 200;
|
|
const SCROLL_THROTTLE = 200;
|
|
const AVATAR_SPARKLES_CENTER_SHIFT = [0, -50] as const;
|
|
|
|
const runThrottledForScroll = throttle((cb) => cb(), SCROLL_THROTTLE, true);
|
|
|
|
const GiftModal: FC<OwnProps & StateProps> = ({
|
|
modal,
|
|
starGiftsById,
|
|
starGiftIdsByCategory,
|
|
myCollectibleGiftsById,
|
|
myCollectibleGiftIds,
|
|
starBalance,
|
|
peer,
|
|
isSelf,
|
|
disallowedGifts,
|
|
resaleGiftsCount,
|
|
areResaleGiftsLoading,
|
|
selectedResaleGift,
|
|
tabId,
|
|
}) => {
|
|
const {
|
|
closeGiftModal,
|
|
openGiftInfoModal,
|
|
resetResaleGifts,
|
|
loadResaleGifts,
|
|
openGiftInMarket,
|
|
closeResaleGiftsMarket,
|
|
loadMyCollectibleGifts,
|
|
openGiftTransferConfirmModal,
|
|
} = getActions();
|
|
const dialogRef = useRef<HTMLDivElement>();
|
|
const transitionRef = useRef<HTMLDivElement>();
|
|
const giftHeaderRef = useRef<HTMLHeadingElement>();
|
|
|
|
const scrollerRef = useRef<HTMLDivElement>();
|
|
|
|
const isOpen = Boolean(modal);
|
|
const renderingModal = useCurrentOrPrev(modal);
|
|
|
|
const user = peer && isApiPeerUser(peer) ? peer : undefined;
|
|
const chat = peer && isApiPeerChat(peer) ? peer : undefined;
|
|
|
|
const [selectedGift, setSelectedGift] = useState<GiftOption | undefined>();
|
|
const [shouldShowMainScreenHeader, setShouldShowMainScreenHeader] = useState(false);
|
|
const [isMainScreenHeaderForStarGifts, setIsMainScreenHeaderForStarGifts] = useState(false);
|
|
const [isGiftScreenHeaderForStarGifts, setIsGiftScreenHeaderForStarGifts] = useState(false);
|
|
|
|
const [selectedCategory, setSelectedCategory] = useState<StarGiftCategory>('all');
|
|
const triggerSparklesRef = useRef<(() => void) | undefined>();
|
|
|
|
const areAllGiftsDisallowed = useMemo(() => {
|
|
if (!disallowedGifts) {
|
|
return undefined;
|
|
}
|
|
const {
|
|
shouldDisallowPremiumGifts,
|
|
...disallowedGiftTypes
|
|
} = disallowedGifts;
|
|
return !isSelf && Object.values(disallowedGiftTypes).every(Boolean);
|
|
}, [isSelf, disallowedGifts]);
|
|
|
|
const areUnlimitedStarGiftsDisallowed = !isSelf && disallowedGifts?.shouldDisallowUnlimitedStarGifts;
|
|
const areLimitedStarGiftsDisallowed = !isSelf && disallowedGifts?.shouldDisallowLimitedStarGifts;
|
|
const areUniqueStarGiftsDisallowed = !isSelf && disallowedGifts?.shouldDisallowUniqueStarGifts;
|
|
|
|
const oldLang = useOldLang();
|
|
const lang = useLang();
|
|
const allGifts = renderingModal?.gifts;
|
|
const filteredGifts = useMemo(() => {
|
|
return allGifts?.sort((prevGift, gift) => prevGift.months - gift.months)
|
|
.filter((gift) => gift.users === 1 && gift.currency !== STARS_CURRENCY_CODE);
|
|
}, [allGifts]);
|
|
|
|
const giftsByStars = useMemo(() => {
|
|
const mapGifts = new Map();
|
|
|
|
if (!filteredGifts) return mapGifts;
|
|
|
|
filteredGifts.forEach((gift) => {
|
|
const giftByStars = allGifts?.find(
|
|
(starsGift) => starsGift.currency === STARS_CURRENCY_CODE
|
|
&& starsGift.months === gift.months,
|
|
);
|
|
if (giftByStars) {
|
|
mapGifts.set(gift, giftByStars);
|
|
}
|
|
});
|
|
|
|
return mapGifts;
|
|
}, [allGifts, filteredGifts]);
|
|
|
|
const baseGift = useMemo(() => {
|
|
return filteredGifts?.reduce((prev, gift) => (prev.amount < gift.amount ? prev : gift));
|
|
}, [filteredGifts]);
|
|
|
|
const {
|
|
observe: observeIntersection,
|
|
} = useIntersectionObserver({ rootRef: scrollerRef, throttleMs: INTERSECTION_THROTTLE, isDisabled: !isOpen });
|
|
|
|
const isResaleScreen = Boolean(selectedResaleGift) && !selectedGift;
|
|
const isGiftScreen = Boolean(selectedGift);
|
|
const shouldShowHeader = isResaleScreen || isGiftScreen || shouldShowMainScreenHeader;
|
|
const isHeaderForStarGifts = isGiftScreen ? isGiftScreenHeaderForStarGifts : isMainScreenHeaderForStarGifts;
|
|
|
|
useEffect(() => {
|
|
if (selectedResaleGift) {
|
|
const giftId = 'regularGiftId' in selectedResaleGift
|
|
? selectedResaleGift.regularGiftId
|
|
: selectedResaleGift.id;
|
|
loadResaleGifts({ giftId });
|
|
}
|
|
}, [selectedResaleGift]);
|
|
|
|
useEffect(() => {
|
|
if (!isOpen) {
|
|
setShouldShowMainScreenHeader(false);
|
|
setSelectedGift(undefined);
|
|
setSelectedCategory('all');
|
|
}
|
|
}, [isOpen, tabId, closeResaleGiftsMarket]);
|
|
|
|
const handleScroll = useLastCallback((e: React.UIEvent<HTMLDivElement>) => {
|
|
if (isGiftScreen) return;
|
|
const currentTarget = e.currentTarget;
|
|
|
|
runThrottledForScroll(() => {
|
|
const { scrollTop } = currentTarget;
|
|
|
|
setShouldShowMainScreenHeader(scrollTop > 150);
|
|
|
|
if (transitionRef.current && giftHeaderRef.current) {
|
|
const { top: headerTop } = giftHeaderRef.current.getBoundingClientRect();
|
|
const { top: transitionTop } = transitionRef.current.getBoundingClientRect();
|
|
setIsMainScreenHeaderForStarGifts(headerTop - transitionTop <= 0);
|
|
}
|
|
});
|
|
});
|
|
|
|
const giftPremiumDescription = lang('GiftPremiumDescription', {
|
|
user: getUserFullName(user)!,
|
|
link: (
|
|
<SafeLink
|
|
text={lang('GiftPremiumDescriptionLinkCaption')}
|
|
url={lang('GiftPremiumDescriptionLink')}
|
|
/>
|
|
),
|
|
}, { withNodes: true });
|
|
|
|
const starGiftDescription = useMemo(() => {
|
|
if (chat) {
|
|
return lang('StarGiftDescriptionChannel', { peer: getPeerTitle(lang, chat) }, {
|
|
withNodes: true,
|
|
withMarkdown: true,
|
|
});
|
|
}
|
|
|
|
if (isSelf) {
|
|
return lang('StarGiftDescriptionSelf', undefined, {
|
|
withNodes: true,
|
|
renderTextFilters: ['br'],
|
|
});
|
|
}
|
|
|
|
if (selectedCategory === 'resale') {
|
|
return lang('StarGiftDescriptionCollectibles');
|
|
}
|
|
|
|
return lang('StarGiftDescription', {
|
|
user: getUserFullName(user)!,
|
|
}, { withNodes: true, withMarkdown: true });
|
|
}, [chat, isSelf, selectedCategory, user, lang]);
|
|
|
|
function renderGiftPremiumHeader() {
|
|
return (
|
|
<h2 className={buildClassName(styles.headerText, styles.center)}>
|
|
{lang('GiftPremiumHeader')}
|
|
</h2>
|
|
);
|
|
}
|
|
|
|
function renderGiftPremiumDescription() {
|
|
return (
|
|
<p className={buildClassName(styles.description, styles.center)}>
|
|
{giftPremiumDescription}
|
|
</p>
|
|
);
|
|
}
|
|
|
|
function renderStarGiftsHeader() {
|
|
return (
|
|
<h2 ref={giftHeaderRef} className={buildClassName(styles.headerText, styles.center)}>
|
|
{lang(isSelf ? 'StarsGiftHeaderSelf' : 'StarsGiftHeader')}
|
|
</h2>
|
|
);
|
|
}
|
|
|
|
function renderStarGiftsDescription() {
|
|
return (
|
|
<p className={buildClassName(styles.description, styles.starGiftsDescription, styles.center)}>
|
|
{starGiftDescription}
|
|
</p>
|
|
);
|
|
}
|
|
|
|
const handleGiftClick = useLastCallback((gift: GiftOption, target?: 'resell' | 'original') => {
|
|
if (target === 'resell') {
|
|
if (!('id' in gift)) {
|
|
return;
|
|
}
|
|
if (isResaleScreen) {
|
|
openGiftInfoModal({ gift, recipientId: renderingModal?.forPeerId });
|
|
return;
|
|
}
|
|
openGiftInMarket({ gift, tabId });
|
|
return;
|
|
}
|
|
setSelectedGift(gift);
|
|
setIsGiftScreenHeaderForStarGifts('id' in gift);
|
|
});
|
|
|
|
const handleMyGiftClick = useLastCallback((gift: ApiStarGift) => {
|
|
if (gift.type === 'starGift' || !myCollectibleGiftsById || !peer?.id) return;
|
|
const savedGift = myCollectibleGiftsById[gift.id];
|
|
|
|
openGiftTransferConfirmModal({
|
|
gift: savedGift,
|
|
recipientId: peer.id,
|
|
});
|
|
});
|
|
|
|
const handleLoadMore = useLastCallback(() => {
|
|
if (selectedCategory === 'myCollectibles') {
|
|
loadMyCollectibleGifts();
|
|
}
|
|
});
|
|
|
|
function renderStarGifts() {
|
|
if (selectedCategory === 'myCollectibles') {
|
|
return (
|
|
<InfiniteScroll
|
|
className={styles.starGiftsContainer}
|
|
items={myCollectibleGiftIds}
|
|
onLoadMore={handleLoadMore}
|
|
scrollContainerClosest={`.${styles.main}`}
|
|
itemSelector=".starGiftItem"
|
|
>
|
|
{myCollectibleGiftsById && myCollectibleGiftIds?.map((giftId) => {
|
|
const savedGift = myCollectibleGiftsById[giftId];
|
|
if (!savedGift) return undefined;
|
|
|
|
return (
|
|
<GiftItemStar
|
|
key={giftId}
|
|
gift={savedGift.gift}
|
|
observeIntersection={observeIntersection}
|
|
onClick={handleMyGiftClick}
|
|
withTransferBadge
|
|
/>
|
|
);
|
|
})}
|
|
</InfiniteScroll>
|
|
);
|
|
}
|
|
|
|
const filteredGiftIds = starGiftIdsByCategory?.[selectedCategory]?.filter((giftId) => {
|
|
const gift = starGiftsById?.[giftId];
|
|
if (!gift) return false;
|
|
|
|
const { isLimited, availabilityResale } = gift;
|
|
|
|
if (areLimitedStarGiftsDisallowed && isLimited) {
|
|
return !areUniqueStarGiftsDisallowed ? availabilityResale : false;
|
|
}
|
|
|
|
if (areUnlimitedStarGiftsDisallowed && !isLimited) return false;
|
|
|
|
return true;
|
|
});
|
|
|
|
return (
|
|
<div className={styles.starGiftsContainer}>
|
|
{starGiftsById && filteredGiftIds?.flatMap((giftId) => {
|
|
const gift = starGiftsById[giftId];
|
|
const shouldShowResale = Boolean(gift.availabilityResale) && !areUniqueStarGiftsDisallowed;
|
|
const shouldDuplicateAsResale = selectedCategory !== 'resale'
|
|
&& shouldShowResale && !gift.isSoldOut && !areLimitedStarGiftsDisallowed;
|
|
|
|
const elements = [
|
|
<GiftItemStar
|
|
key={giftId}
|
|
gift={gift}
|
|
observeIntersection={observeIntersection}
|
|
isResale={shouldShowResale && !shouldDuplicateAsResale}
|
|
onClick={handleGiftClick}
|
|
/>,
|
|
];
|
|
|
|
if (shouldDuplicateAsResale) {
|
|
elements.push(
|
|
<GiftItemStar
|
|
key={`resale_${giftId}`}
|
|
isResale
|
|
gift={gift}
|
|
observeIntersection={observeIntersection}
|
|
onClick={handleGiftClick}
|
|
/>,
|
|
);
|
|
}
|
|
|
|
return elements;
|
|
})}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function renderPremiumGifts() {
|
|
return (
|
|
<div className={styles.premiumGiftsGallery}>
|
|
{filteredGifts?.map((gift) => {
|
|
return (
|
|
<GiftItemPremium
|
|
option={gift}
|
|
optionByStars={giftsByStars.get(gift)}
|
|
baseMonthAmount={baseGift ? Math.floor(baseGift.amount / baseGift.months) : undefined}
|
|
onClick={handleGiftClick}
|
|
/>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const onCategoryChanged = useLastCallback((category: StarGiftCategory) => {
|
|
setSelectedCategory(category);
|
|
});
|
|
|
|
const handleCloseModal = useLastCallback(() => {
|
|
setSelectedGift(undefined);
|
|
resetResaleGifts();
|
|
closeGiftModal();
|
|
});
|
|
|
|
const handleCloseButtonClick = useLastCallback(() => {
|
|
if (isResaleScreen) {
|
|
closeResaleGiftsMarket({ tabId });
|
|
return;
|
|
}
|
|
if (isGiftScreen) {
|
|
setSelectedGift(undefined);
|
|
return;
|
|
}
|
|
handleCloseModal();
|
|
});
|
|
|
|
const handleAvatarMouseMove = useLastCallback(() => {
|
|
triggerSparklesRef.current?.();
|
|
});
|
|
|
|
const handleRequestAnimation = useLastCallback((animate: NoneToVoidFunction) => {
|
|
triggerSparklesRef.current = animate;
|
|
});
|
|
|
|
function renderMainScreen() {
|
|
return (
|
|
<div ref={scrollerRef} className={buildClassName(styles.main, 'custom-scroll')} onScroll={handleScroll}>
|
|
<div className={styles.avatars}>
|
|
<Avatar
|
|
className={styles.avatar}
|
|
size={AVATAR_SIZE}
|
|
peer={peer}
|
|
onMouseMove={handleAvatarMouseMove}
|
|
/>
|
|
<InteractiveSparkles
|
|
className={styles.logoBackground}
|
|
color="gold"
|
|
centerShift={AVATAR_SPARKLES_CENTER_SHIFT}
|
|
onRequestAnimation={handleRequestAnimation}
|
|
/>
|
|
</div>
|
|
{!isSelf && !chat && !disallowedGifts?.shouldDisallowPremiumGifts && (
|
|
<>
|
|
{renderGiftPremiumHeader()}
|
|
{renderGiftPremiumDescription()}
|
|
{renderPremiumGifts()}
|
|
</>
|
|
)}
|
|
|
|
{!areAllGiftsDisallowed && (
|
|
<>
|
|
{renderStarGiftsHeader()}
|
|
{renderStarGiftsDescription()}
|
|
<StarGiftCategoryList
|
|
areCollectibleStarGiftsDisallowed={areUniqueStarGiftsDisallowed}
|
|
isSelf={isSelf}
|
|
hasCollectible={Boolean(myCollectibleGiftIds?.length)}
|
|
onCategoryChanged={onCategoryChanged}
|
|
/>
|
|
<Transition
|
|
name="zoomFade"
|
|
activeKey={getCategoryKey(selectedCategory)}
|
|
className={styles.starGiftsTransition}
|
|
>
|
|
{renderStarGifts()}
|
|
</Transition>
|
|
</>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const isBackButton = isGiftScreen || isResaleScreen;
|
|
|
|
const buttonClassName = buildClassName(
|
|
'animated-close-icon',
|
|
isBackButton && 'state-back',
|
|
);
|
|
|
|
function renderHeader() {
|
|
if (!shouldShowHeader) return undefined;
|
|
if (isResaleScreen) {
|
|
const isFirstLoading = areResaleGiftsLoading && !resaleGiftsCount;
|
|
return (
|
|
<div className={styles.resaleHeaderContentContainer}>
|
|
<h2 className={styles.resaleHeaderText}>
|
|
{selectedResaleGift.title}
|
|
</h2>
|
|
{isFirstLoading
|
|
&& (
|
|
<div className={styles.resaleHeaderDescription}>
|
|
{lang('Loading')}
|
|
</div>
|
|
)}
|
|
{!isFirstLoading && resaleGiftsCount !== undefined
|
|
&& (
|
|
<div className={styles.resaleHeaderDescription}>
|
|
{lang('HeaderDescriptionResaleGifts', {
|
|
count: resaleGiftsCount,
|
|
}, { withNodes: true, withMarkdown: true, pluralValue: resaleGiftsCount })}
|
|
</div>
|
|
)}
|
|
<GiftResaleFilters dialogRef={dialogRef} />
|
|
</div>
|
|
);
|
|
}
|
|
return (
|
|
<h2 className={styles.commonHeaderText}>
|
|
{lang(isHeaderForStarGifts ? (isSelf ? 'StarsGiftHeaderSelf' : 'StarsGiftHeader') : 'GiftPremiumHeader')}
|
|
</h2>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Modal
|
|
dialogRef={dialogRef}
|
|
onClose={handleCloseModal}
|
|
isOpen={isOpen}
|
|
isSlim
|
|
contentClassName={styles.content}
|
|
className={buildClassName(styles.modalDialog, styles.root)}
|
|
isLowStackPriority
|
|
>
|
|
<Button
|
|
className={styles.closeButton}
|
|
round
|
|
color="translucent"
|
|
size="smaller"
|
|
onClick={handleCloseButtonClick}
|
|
ariaLabel={isBackButton ? oldLang('Common.Back') : oldLang('Common.Close')}
|
|
>
|
|
<div className={buttonClassName} />
|
|
</Button>
|
|
<BalanceBlock className={styles.balance} balance={starBalance} withAddButton />
|
|
<div className={buildClassName(
|
|
styles.header,
|
|
isResaleScreen && styles.resaleHeader,
|
|
!shouldShowHeader && styles.hiddenHeader)}
|
|
>
|
|
<Transition
|
|
name="slideVerticalFade"
|
|
activeKey={!shouldShowHeader ? 0 : isResaleScreen ? 1 : isHeaderForStarGifts ? 2 : 3}
|
|
slideClassName={styles.headerSlide}
|
|
>
|
|
{renderHeader()}
|
|
</Transition>
|
|
</div>
|
|
<Transition
|
|
ref={transitionRef}
|
|
className={styles.transition}
|
|
name="pushSlide"
|
|
activeKey={isGiftScreen ? 1 : isResaleScreen ? 2 : 0}
|
|
>
|
|
{!isGiftScreen && !isResaleScreen && renderMainScreen()}
|
|
{isResaleScreen && selectedResaleGift
|
|
&& (
|
|
<GiftModalResaleScreen
|
|
onGiftClick={handleGiftClick}
|
|
/>
|
|
)}
|
|
{isGiftScreen && renderingModal?.forPeerId && (
|
|
<GiftSendingOptions
|
|
gift={selectedGift}
|
|
giftByStars={giftsByStars.get(selectedGift)}
|
|
peerId={renderingModal.forPeerId}
|
|
/>
|
|
)}
|
|
</Transition>
|
|
</Modal>
|
|
);
|
|
};
|
|
|
|
export default memo(withGlobal<OwnProps>((global, { modal }): Complete<StateProps> => {
|
|
const {
|
|
starGifts,
|
|
stars,
|
|
currentUserId,
|
|
} = global;
|
|
|
|
const peer = modal?.forPeerId ? selectPeer(global, modal.forPeerId) : undefined;
|
|
const isSelf = Boolean(currentUserId && modal?.forPeerId === currentUserId);
|
|
const userFullInfo = peer ? selectUserFullInfo(global, peer?.id) : undefined;
|
|
|
|
const { resaleGifts } = selectTabState(global);
|
|
const resaleGiftsCount = resaleGifts.count;
|
|
const areResaleGiftsLoading = resaleGifts.isLoading !== false;
|
|
const selectedResaleGift = modal?.selectedResaleGift;
|
|
|
|
return {
|
|
boostPerSentGift: global.appConfig.boostsPerSentGift,
|
|
starGiftsById: starGifts?.byId,
|
|
starGiftIdsByCategory: starGifts?.idsByCategory,
|
|
myCollectibleGiftsById: global.myCollectibleGifts?.byId,
|
|
myCollectibleGiftIds: global.myCollectibleGifts?.ids,
|
|
starBalance: stars?.balance,
|
|
peer,
|
|
isSelf,
|
|
disallowedGifts: userFullInfo?.disallowedGifts,
|
|
resaleGiftsCount,
|
|
areResaleGiftsLoading,
|
|
selectedResaleGift,
|
|
tabId: selectTabState(global).id,
|
|
};
|
|
})(GiftModal));
|
|
|
|
function getCategoryKey(category: StarGiftCategory) {
|
|
if (category === 'all') return 0;
|
|
if (category === 'myCollectibles') return 1;
|
|
return 2;
|
|
}
|