Stars Gifting: Fixes for Stars Gifting (#4899)
This commit is contained in:
parent
1dfcbf1009
commit
e1504323f1
@ -8,7 +8,7 @@ import type {
|
||||
ApiGiveawayInfo,
|
||||
ApiInvoice, ApiLabeledPrice, ApiMyBoost, ApiPaymentCredentials,
|
||||
ApiPaymentForm, ApiPaymentSavedInfo, ApiPremiumGiftCodeOption, ApiPremiumPromo, ApiPremiumSubscriptionOption,
|
||||
ApiReceipt, ApiStarsGiftOption,
|
||||
ApiReceipt,
|
||||
ApiStarsTransaction,
|
||||
ApiStarsTransactionPeer,
|
||||
ApiStarTopupOption,
|
||||
@ -386,7 +386,7 @@ export function buildApiPremiumGiftCodeOption(option: GramJs.PremiumGiftCodeOpti
|
||||
};
|
||||
}
|
||||
|
||||
export function buildApiStarsGiftOptions(option: GramJs.StarsGiftOption): ApiStarsGiftOption {
|
||||
export function buildApiStarsGiftOptions(option: GramJs.StarsGiftOption): ApiStarTopupOption {
|
||||
const {
|
||||
extended, stars, amount, currency,
|
||||
} = option;
|
||||
|
||||
@ -159,13 +159,6 @@ export interface ApiPremiumGiftCodeOption {
|
||||
amount: number;
|
||||
}
|
||||
|
||||
export interface ApiStarsGiftOption {
|
||||
isExtended?: true;
|
||||
stars: number;
|
||||
currency: string;
|
||||
amount: number;
|
||||
}
|
||||
|
||||
export type ApiBoostsStatus = {
|
||||
level: number;
|
||||
currentLevelBoosts: number;
|
||||
|
||||
@ -135,6 +135,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.size-huge {
|
||||
width: 6rem;
|
||||
height: 6rem;
|
||||
font-size: 3rem;
|
||||
|
||||
.emoji {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
&.size-jumbo {
|
||||
width: 7.5rem;
|
||||
height: 7.5rem;
|
||||
|
||||
@ -45,7 +45,8 @@ import './Avatar.scss';
|
||||
|
||||
const LOOP_COUNT = 3;
|
||||
|
||||
export type AvatarSize = 'micro' | 'tiny' | 'mini' | 'small' | 'small-mobile' | 'medium' | 'large' | 'giant' | 'jumbo';
|
||||
export type AvatarSize =
|
||||
'micro' | 'tiny' | 'mini' | 'small' | 'small-mobile' | 'medium' | 'large' | 'giant' | 'huge' | 'jumbo';
|
||||
|
||||
const cn = createClassNameBuilder('Avatar');
|
||||
cn.media = cn('media');
|
||||
|
||||
@ -36,6 +36,10 @@
|
||||
--size: 3.375rem;
|
||||
}
|
||||
|
||||
.size-huge {
|
||||
--size: 6.5rem;
|
||||
}
|
||||
|
||||
.size-jumbo {
|
||||
--size: 7.5rem;
|
||||
}
|
||||
|
||||
@ -37,6 +37,7 @@ const SIZES: Record<AvatarSize, number> = {
|
||||
medium: 2.875 * REM,
|
||||
large: 3.5 * REM,
|
||||
giant: 5.125 * REM,
|
||||
huge: 6.125 * REM,
|
||||
jumbo: 7.625 * REM,
|
||||
};
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
|
||||
import type { LangFn } from '../../../hooks/useOldLang';
|
||||
import type { TextPart } from '../../../types';
|
||||
|
||||
import { SERVICE_NOTIFICATIONS_USER_ID } from '../../../config';
|
||||
import {
|
||||
getChatTitle,
|
||||
getExpiredMessageDescription,
|
||||
@ -111,7 +112,9 @@ export function renderActionMessageText(
|
||||
actionOriginChat ? (
|
||||
renderChatContent(lang, actionOriginChat, noLinks) || NBSP
|
||||
) : actionOriginUser ? (
|
||||
renderUserContent(actionOriginUser, noLinks) || NBSP
|
||||
actionOriginUser.id === SERVICE_NOTIFICATIONS_USER_ID
|
||||
? lang('StarsTransactionUnknown')
|
||||
: renderUserContent(actionOriginUser, noLinks) || NBSP
|
||||
) : 'User',
|
||||
'',
|
||||
);
|
||||
|
||||
@ -28,6 +28,7 @@ const PickerModal = ({
|
||||
...modalProps
|
||||
}: OwnProps) => {
|
||||
const lang = useOldLang();
|
||||
const hasOnClickHandler = Boolean(onConfirm || modalProps.onClose);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@ -43,17 +44,19 @@ const PickerModal = ({
|
||||
headerClassName={buildClassName(styles.header, modalProps.headerClassName)}
|
||||
>
|
||||
{modalProps.children}
|
||||
<div className={styles.buttonWrapper}>
|
||||
<Button
|
||||
withPremiumGradient={withPremiumGradient}
|
||||
onClick={onConfirm || modalProps.onClose}
|
||||
color="primary"
|
||||
size="smaller"
|
||||
disabled={isConfirmDisabled}
|
||||
>
|
||||
{confirmButtonText || lang('Confirm')}
|
||||
</Button>
|
||||
</div>
|
||||
{hasOnClickHandler && (
|
||||
<div className={styles.buttonWrapper}>
|
||||
<Button
|
||||
withPremiumGradient={withPremiumGradient}
|
||||
onClick={onConfirm || modalProps.onClose}
|
||||
color="primary"
|
||||
size="smaller"
|
||||
disabled={isConfirmDisabled}
|
||||
>
|
||||
{confirmButtonText || lang('Confirm')}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
@ -86,6 +86,7 @@ const PremiumGiftingPickerModal: FC<OwnProps & StateProps> = ({
|
||||
onConfirm={handleSendIdList}
|
||||
onEnter={handleSendIdList}
|
||||
withPremiumGradient
|
||||
isConfirmDisabled={!selectedUserIds?.length}
|
||||
>
|
||||
<PeerPicker
|
||||
className={styles.picker}
|
||||
|
||||
@ -30,7 +30,39 @@
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.headerInfo {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin: 1rem;
|
||||
width: 6.25rem;
|
||||
height: 6.25rem;
|
||||
min-height: 6.25rem;
|
||||
}
|
||||
|
||||
.logoBackground {
|
||||
position: absolute;
|
||||
top: 0.75rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
height: 8rem;
|
||||
}
|
||||
|
||||
.description {
|
||||
text-align: center;
|
||||
margin-inline: 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
.section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
@ -67,41 +99,24 @@
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.avatars {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
margin: 1rem;
|
||||
.avatar {
|
||||
margin: 2rem;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.options {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 0.5rem;
|
||||
width: 100%;
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
.boostIcon {
|
||||
color: var(--color-primary);
|
||||
vertical-align: middle;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.moreOptions {
|
||||
grid-column: 1/-1;
|
||||
}
|
||||
|
||||
.secondaryInfo {
|
||||
text-align: center;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-secondary);
|
||||
padding: 0.5rem 1rem;
|
||||
padding: 1rem;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
@media (max-width: 450px) {
|
||||
.modalDialog :global(.modal-dialog) {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,9 +6,10 @@ import React, {
|
||||
import { getActions, getGlobal, withGlobal } from '../../../global';
|
||||
|
||||
import type {
|
||||
ApiStarsGiftOption, ApiStarTopupOption, ApiUser,
|
||||
ApiStarTopupOption, ApiUser,
|
||||
} from '../../../api/types';
|
||||
|
||||
import { getSenderTitle } from '../../../global/helpers';
|
||||
import {
|
||||
selectTabState, selectUser,
|
||||
} from '../../../global/selectors';
|
||||
@ -27,13 +28,16 @@ import Modal from '../../ui/Modal';
|
||||
|
||||
import styles from './StarsGiftModal.module.scss';
|
||||
|
||||
import StarLogo from '../../../assets/icons/StarLogo.svg';
|
||||
import StarsBackground from '../../../assets/stars-bg.png';
|
||||
|
||||
export type OwnProps = {
|
||||
isOpen?: boolean;
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
isCompleted?: boolean;
|
||||
starsGiftOptions?: ApiStarsGiftOption[] | undefined;
|
||||
starsGiftOptions?: ApiStarTopupOption[] | undefined;
|
||||
forUserId?: string;
|
||||
user?: ApiUser;
|
||||
};
|
||||
@ -88,13 +92,22 @@ const StarsGiftModal: FC<OwnProps & StateProps> = ({
|
||||
|
||||
const handleClick = useLastCallback((option: ApiStarTopupOption) => {
|
||||
setSelectedOption(option);
|
||||
openInvoice({
|
||||
type: 'starsgift',
|
||||
userId: forUserId!,
|
||||
stars: option.stars,
|
||||
currency: option.currency,
|
||||
amount: option.amount,
|
||||
});
|
||||
if (user) {
|
||||
openInvoice({
|
||||
type: 'starsgift',
|
||||
userId: forUserId!,
|
||||
stars: option.stars,
|
||||
currency: option.currency,
|
||||
amount: option.amount,
|
||||
});
|
||||
} else {
|
||||
openInvoice({
|
||||
type: 'stars',
|
||||
stars: option.stars,
|
||||
currency: option.currency,
|
||||
amount: option.amount,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function handleScroll(e: React.UIEvent<HTMLDivElement>) {
|
||||
@ -105,11 +118,12 @@ const StarsGiftModal: FC<OwnProps & StateProps> = ({
|
||||
|
||||
function renderGiftTitle() {
|
||||
if (isCompleted) {
|
||||
return renderText(oldLang('Notification.StarsGift.SentYou',
|
||||
formatCurrencyAsString(selectedOption!.amount, selectedOption!.currency, oldLang.code)), ['simple_markdown']);
|
||||
return user ? renderText(oldLang('Notification.StarsGift.SentYou',
|
||||
formatCurrencyAsString(selectedOption!.amount, selectedOption!.currency, oldLang.code)), ['simple_markdown'])
|
||||
: renderText(oldLang('StarsAcquiredInfo', selectedOption?.stars), ['simple_markdown']);
|
||||
}
|
||||
|
||||
return oldLang('GiftStarsTitle');
|
||||
return user ? oldLang('GiftStarsTitle') : oldLang('Star.List.GetStars');
|
||||
}
|
||||
|
||||
function renderStarOptionList() {
|
||||
@ -154,28 +168,40 @@ const StarsGiftModal: FC<OwnProps & StateProps> = ({
|
||||
</Button>
|
||||
<div className={buildClassName(styles.header, isHeaderHidden && styles.hiddenHeader)}>
|
||||
<h2 className={styles.starHeaderText}>
|
||||
{oldLang('GiftStarsTitle')}
|
||||
{user ? oldLang('GiftStarsTitle') : oldLang('Star.List.GetStars')}
|
||||
</h2>
|
||||
</div>
|
||||
<div className={styles.avatars}>
|
||||
<Avatar
|
||||
size="large"
|
||||
peer={user}
|
||||
/>
|
||||
<div className={styles.headerInfo}>
|
||||
{user ? (
|
||||
<>
|
||||
<Avatar
|
||||
size="huge"
|
||||
peer={user}
|
||||
className={styles.avatar}
|
||||
/>
|
||||
<img className={styles.logoBackground} src={StarsBackground} alt="" draggable={false} />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<img className={styles.logo} src={StarLogo} alt="" draggable={false} />
|
||||
<img className={styles.logoBackground} src={StarsBackground} alt="" draggable={false} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<h2 className={buildClassName(styles.headerText, styles.center)}>
|
||||
{renderGiftTitle()}
|
||||
</h2>
|
||||
{!isCompleted && (
|
||||
<>
|
||||
<div className={buildClassName(styles.section, styles.options)}>
|
||||
{renderStarOptionList()}
|
||||
</div>
|
||||
<div className={styles.secondaryInfo}>
|
||||
{bottomText}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<p className={styles.description}>
|
||||
{user ? renderText(
|
||||
oldLang('ActionGiftStarsSubtitle', getSenderTitle(oldLang, user)), ['simple_markdown'],
|
||||
) : oldLang('Stars.Purchase.GetStarsInfo')}
|
||||
</p>
|
||||
<div className={styles.section}>
|
||||
{renderStarOptionList()}
|
||||
<div className={styles.secondaryInfo}>
|
||||
{bottomText}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import React, {
|
||||
memo, useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from '../../../lib/teact/teact';
|
||||
import { getActions, getGlobal, withGlobal } from '../../../global';
|
||||
@ -10,17 +9,14 @@ import { SERVICE_NOTIFICATIONS_USER_ID } from '../../../config';
|
||||
import {
|
||||
filterUsersByName, isDeletedUser, isUserBot,
|
||||
} from '../../../global/helpers';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import { unique } from '../../../util/iteratees';
|
||||
import sortChatIds from '../../common/helpers/sortChatIds';
|
||||
|
||||
import useLastCallback from '../../../hooks/useLastCallback';
|
||||
import useOldLang from '../../../hooks/useOldLang';
|
||||
|
||||
import Icon from '../../common/icons/Icon';
|
||||
import PeerPicker from '../../common/pickers/PeerPicker';
|
||||
import Button from '../../ui/Button';
|
||||
import Modal from '../../ui/Modal';
|
||||
import PickerModal from '../../common/pickers/PickerModal';
|
||||
|
||||
import styles from './StarsGiftingPickerModal.module.scss';
|
||||
|
||||
@ -42,8 +38,6 @@ const StarsGiftingPickerModal: FC<OwnProps & StateProps> = ({
|
||||
archivedListIds,
|
||||
userIds,
|
||||
}) => {
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const dialogRef = useRef<HTMLDivElement>(null);
|
||||
const { closeStarsGiftingModal, openStarsGiftModal } = getActions();
|
||||
|
||||
const oldLang = useOldLang();
|
||||
@ -79,48 +73,30 @@ const StarsGiftingPickerModal: FC<OwnProps & StateProps> = ({
|
||||
}
|
||||
});
|
||||
|
||||
function renderHeaderText() {
|
||||
return (
|
||||
<div className={styles.filter} dir={oldLang.isRtl ? 'rtl' : undefined}>
|
||||
<Button
|
||||
round
|
||||
size="smaller"
|
||||
color="translucent"
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => closeStarsGiftingModal()}
|
||||
ariaLabel={oldLang('Close')}
|
||||
>
|
||||
<Icon name="close" />
|
||||
</Button>
|
||||
<h3 className={buildClassName(styles.title, 'ml-2')}>{oldLang('GiftStarsTitle')}
|
||||
</h3>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
<PickerModal
|
||||
className={styles.root}
|
||||
isOpen={isOpen}
|
||||
onClose={closeStarsGiftingModal}
|
||||
onEnter={handleSelectedUserIdsChange}
|
||||
dialogRef={dialogRef}
|
||||
title={oldLang('GiftStarsTitle')}
|
||||
hasCloseButton
|
||||
shouldAdaptToSearch
|
||||
withFixedHeight
|
||||
confirmButtonText={oldLang('Continue')}
|
||||
onEnter={closeStarsGiftingModal}
|
||||
>
|
||||
<div className={buildClassName(styles.main, 'custom-scroll')}>
|
||||
{renderHeaderText()}
|
||||
<PeerPicker
|
||||
className={styles.picker}
|
||||
itemIds={displayedUserIds}
|
||||
filterValue={searchQuery}
|
||||
filterPlaceholder={oldLang('Search')}
|
||||
onFilterChange={setSearchQuery}
|
||||
isSearchable
|
||||
withDefaultPadding
|
||||
withStatus
|
||||
onSelectedIdChange={handleSelectedUserIdsChange}
|
||||
/>
|
||||
</div>
|
||||
</Modal>
|
||||
<PeerPicker
|
||||
className={styles.picker}
|
||||
itemIds={displayedUserIds}
|
||||
filterValue={searchQuery}
|
||||
filterPlaceholder={oldLang('Search')}
|
||||
onFilterChange={setSearchQuery}
|
||||
isSearchable
|
||||
withDefaultPadding
|
||||
withStatus
|
||||
onSelectedIdChange={handleSelectedUserIdsChange}
|
||||
/>
|
||||
</PickerModal>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -21,12 +21,14 @@ import {
|
||||
selectChat,
|
||||
selectChatMessage,
|
||||
selectGiftStickerForDuration,
|
||||
selectGiftStickerForStars,
|
||||
selectIsMessageFocused,
|
||||
selectTabState,
|
||||
selectTopicFromMessage,
|
||||
selectUser,
|
||||
} from '../../global/selectors';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
import { formatInteger } from '../../util/textFormat';
|
||||
import { renderActionMessageText } from '../common/helpers/renderActionMessageText';
|
||||
import renderText from '../common/helpers/renderText';
|
||||
import { preventMessageInputBlur } from './helpers/preventMessageInputBlur';
|
||||
@ -72,6 +74,7 @@ type StateProps = {
|
||||
focusDirection?: FocusDirection;
|
||||
noFocusHighlight?: boolean;
|
||||
premiumGiftSticker?: ApiSticker;
|
||||
starGiftSticker?: ApiSticker;
|
||||
canPlayAnimatedEmojis?: boolean;
|
||||
};
|
||||
|
||||
@ -93,6 +96,7 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
|
||||
focusDirection,
|
||||
noFocusHighlight,
|
||||
premiumGiftSticker,
|
||||
starGiftSticker,
|
||||
isInsideTopic,
|
||||
topic,
|
||||
memoFirstUnreadIdRef,
|
||||
@ -315,15 +319,16 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
|
||||
>
|
||||
<AnimatedIconFromSticker
|
||||
key={message.id}
|
||||
sticker={premiumGiftSticker}
|
||||
sticker={starGiftSticker}
|
||||
play={canPlayAnimatedEmojis}
|
||||
noLoop
|
||||
nonInteractive
|
||||
/>
|
||||
<strong>
|
||||
{oldLang('Stars', message.content.action!.stars)}
|
||||
</strong>
|
||||
<span className="action-message-subtitle">
|
||||
<div className="action-message-stars-balance">
|
||||
{formatInteger(message.content.action!.stars!)}
|
||||
<strong>{oldLang('Stars')}</strong>
|
||||
</div>
|
||||
<span className="action-message-stars-subtitle">
|
||||
{renderText(
|
||||
oldLang(!message.isOutgoing
|
||||
? 'ActionGiftStarsSubtitleYou' : 'ActionGiftStarsSubtitle', getChatTitle(oldLang, targetChat!)),
|
||||
@ -406,6 +411,10 @@ export default memo(withGlobal<OwnProps>(
|
||||
|
||||
const giftDuration = content.action?.months;
|
||||
const premiumGiftSticker = selectGiftStickerForDuration(global, giftDuration);
|
||||
|
||||
const starCount = content.action?.stars;
|
||||
const starGiftSticker = selectGiftStickerForStars(global, starCount);
|
||||
|
||||
const topic = selectTopicFromMessage(global, message);
|
||||
|
||||
return {
|
||||
@ -417,6 +426,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
targetMessage,
|
||||
isFocused,
|
||||
premiumGiftSticker,
|
||||
starGiftSticker,
|
||||
topic,
|
||||
canPlayAnimatedEmojis: selectCanPlayAnimatedEmojis(global),
|
||||
...(isFocused && {
|
||||
|
||||
@ -273,7 +273,7 @@
|
||||
}
|
||||
|
||||
.action-message-gift-code {
|
||||
width: 20rem;
|
||||
width: 12rem;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
@ -282,12 +282,25 @@
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
.action-message-stars-balance {
|
||||
margin-top: 0.5rem;
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
line-height: 1.5;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.action-message-subtitle {
|
||||
margin-top: 1rem;
|
||||
font-weight: normal;
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
.action-message-stars-subtitle {
|
||||
font-weight: normal;
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
.action-message-suggested-avatar {
|
||||
max-width: 16rem;
|
||||
display: flex !important;
|
||||
|
||||
@ -30,6 +30,7 @@ type OwnProps = {
|
||||
headerAvatarPeer?: ApiPeer | CustomPeer;
|
||||
headerAvatarWebPhoto?: ApiWebDocument;
|
||||
noHeaderImage?: boolean;
|
||||
isGift?: boolean;
|
||||
header?: TeactNode;
|
||||
footer?: TeactNode;
|
||||
buttonText?: string;
|
||||
@ -47,6 +48,7 @@ const TableInfoModal = ({
|
||||
headerAvatarPeer,
|
||||
headerAvatarWebPhoto,
|
||||
noHeaderImage,
|
||||
isGift,
|
||||
header,
|
||||
footer,
|
||||
buttonText,
|
||||
@ -73,7 +75,7 @@ const TableInfoModal = ({
|
||||
contentClassName={styles.content}
|
||||
onClose={onClose}
|
||||
>
|
||||
{!noHeaderImage && (
|
||||
{!isGift && !noHeaderImage && (
|
||||
withAvatar ? (
|
||||
<Avatar peer={headerAvatarPeer} webPhoto={headerAvatarWebPhoto} size="jumbo" className={styles.avatar} />
|
||||
) : (
|
||||
|
||||
@ -1,5 +1,12 @@
|
||||
@use '../../../styles/mixins';
|
||||
|
||||
.options {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 0.5rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.option {
|
||||
--_background-color: var(--color-background-secondary);
|
||||
display: flex;
|
||||
@ -60,3 +67,9 @@
|
||||
margin-inline-start: 0.25rem;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
@media (max-width: 450px) {
|
||||
.optionTop {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@ const StarTopupOptionList: FC<OwnProps> = ({
|
||||
}, [areOptionsExtended, options, starsNeeded]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.options}>
|
||||
{renderingOptions?.map(({ option, starsCount, isWide }) => {
|
||||
const length = renderingOptions?.length;
|
||||
const isOdd = length % 2 === 0;
|
||||
@ -103,7 +103,7 @@ const StarTopupOptionList: FC<OwnProps> = ({
|
||||
<Icon className={styles.iconDown} name="down" />
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -136,23 +136,10 @@
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.options {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 0.5rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.optionFullWidth {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.starButton {
|
||||
grid-column: 1/-1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.paymentContent {
|
||||
|
||||
@ -3,7 +3,7 @@ import React, {
|
||||
} from '../../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
import type { ApiStarTopupOption, ApiUser } from '../../../api/types';
|
||||
import type { ApiUser } from '../../../api/types';
|
||||
import type { GlobalState, TabState } from '../../../global/types';
|
||||
|
||||
import { getUserFullName } from '../../../global/helpers';
|
||||
@ -24,7 +24,6 @@ import Modal from '../../ui/Modal';
|
||||
import TabList, { type TabWithProperties } from '../../ui/TabList';
|
||||
import Transition from '../../ui/Transition';
|
||||
import BalanceBlock from './BalanceBlock';
|
||||
import StarTopupOptionList from './StarTopupOptionList';
|
||||
import TransactionItem from './transaction/StarsTransactionItem';
|
||||
|
||||
import styles from './StarsBalanceModal.module.scss';
|
||||
@ -53,10 +52,10 @@ const StarsBalanceModal = ({
|
||||
modal, starsBalanceState, originPaymentBot, canBuyPremium,
|
||||
}: OwnProps & StateProps) => {
|
||||
const {
|
||||
closeStarsBalanceModal, loadStarsTransactions, openInvoice, openStarsGiftingModal,
|
||||
closeStarsBalanceModal, loadStarsTransactions, openStarsGiftingModal, openStarsGiftModal,
|
||||
} = getActions();
|
||||
|
||||
const { balance, history, topupOptions } = starsBalanceState || {};
|
||||
const { balance, history } = starsBalanceState || {};
|
||||
|
||||
const oldLang = useOldLang();
|
||||
const lang = useLang();
|
||||
@ -96,36 +95,20 @@ const StarsBalanceModal = ({
|
||||
setHeaderHidden(scrollTop <= 150);
|
||||
}
|
||||
|
||||
const handleClick = useLastCallback((option: ApiStarTopupOption) => {
|
||||
openInvoice({
|
||||
type: 'stars',
|
||||
stars: option.stars,
|
||||
currency: option.currency,
|
||||
amount: option.amount,
|
||||
});
|
||||
});
|
||||
|
||||
function renderStarOptionList() {
|
||||
return (
|
||||
<StarTopupOptionList
|
||||
isActive={isOpen}
|
||||
options={topupOptions}
|
||||
starsNeeded={starsNeeded}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const handleLoadMore = useLastCallback(() => {
|
||||
loadStarsTransactions({
|
||||
type: TRANSACTION_TYPES[selectedTabIndex],
|
||||
});
|
||||
});
|
||||
|
||||
const openPremiumGiftingModalHandler = useLastCallback(() => {
|
||||
const openStarsGiftingModalHandler = useLastCallback(() => {
|
||||
openStarsGiftingModal({});
|
||||
});
|
||||
|
||||
const openStarsInfoModalHandler = useLastCallback(() => {
|
||||
openStarsGiftModal({});
|
||||
});
|
||||
|
||||
return (
|
||||
<Modal className={styles.root} isOpen={isOpen} onClose={closeStarsBalanceModal}>
|
||||
<div className={buildClassName(styles.main, 'custom-scroll')} onScroll={handleScroll}>
|
||||
@ -158,19 +141,24 @@ const StarsBalanceModal = ({
|
||||
['simple_markdown', 'emoji'],
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.options}>
|
||||
{renderStarOptionList()}
|
||||
{canBuyPremium && (
|
||||
<Button
|
||||
className={buildClassName(styles.starButton, 'settings-main-menu-star')}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={openPremiumGiftingModalHandler}
|
||||
>
|
||||
<StarIcon className="icon" type="gold" size="big" />
|
||||
{oldLang('TelegramStarsGift')}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
{canBuyPremium && (
|
||||
<Button
|
||||
className={styles.starButton}
|
||||
onClick={openStarsInfoModalHandler}
|
||||
>
|
||||
{oldLang('Star.List.BuyMoreStars')}
|
||||
</Button>
|
||||
)}
|
||||
{canBuyPremium && (
|
||||
<Button
|
||||
className={buildClassName(styles.starButton, 'settings-main-menu-star')}
|
||||
color="translucent"
|
||||
onClick={openStarsGiftingModalHandler}
|
||||
>
|
||||
<StarIcon className="icon" type="gold" size="big" />
|
||||
{oldLang('TelegramStarsGift')}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.secondaryInfo}>
|
||||
{tosText}
|
||||
|
||||
@ -2,6 +2,10 @@
|
||||
z-index: calc(var(--z-media-viewer) - 1);
|
||||
}
|
||||
|
||||
.modal :global(.modal-dialog) {
|
||||
max-width: 26rem !important;
|
||||
}
|
||||
|
||||
.positive {
|
||||
color: var(--color-success);
|
||||
}
|
||||
@ -19,10 +23,14 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.starsHeader {
|
||||
gap: normal;
|
||||
}
|
||||
|
||||
.amount {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
font-size: 1.25rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.325;
|
||||
}
|
||||
@ -44,6 +52,7 @@
|
||||
.footer {
|
||||
text-align: center;
|
||||
margin-block: 0.5rem;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.starsBackground {
|
||||
@ -67,3 +76,12 @@
|
||||
margin-bottom: 2rem;
|
||||
cursor: var(--custom-cursor, pointer);
|
||||
}
|
||||
|
||||
.starTitle {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
text-align: center;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
@ -4,22 +4,29 @@ import { getActions, withGlobal } from '../../../../global';
|
||||
|
||||
import type {
|
||||
ApiPeer,
|
||||
ApiStarsTransactionPeer,
|
||||
ApiStarsTransactionPeer, ApiSticker, ApiUser,
|
||||
} from '../../../../api/types';
|
||||
import type { TabState } from '../../../../global/types';
|
||||
import { MediaViewerOrigin } from '../../../../types';
|
||||
|
||||
import { getMessageLink } from '../../../../global/helpers';
|
||||
import { getMessageLink, getUserFullName } from '../../../../global/helpers';
|
||||
import { buildStarsTransactionCustomPeer, formatStarsTransactionAmount } from '../../../../global/helpers/payments';
|
||||
import { selectPeer } from '../../../../global/selectors';
|
||||
import {
|
||||
selectCanPlayAnimatedEmojis,
|
||||
selectGiftStickerForStars,
|
||||
selectPeer, selectUser,
|
||||
} from '../../../../global/selectors';
|
||||
import buildClassName from '../../../../util/buildClassName';
|
||||
import { copyTextToClipboard } from '../../../../util/clipboard';
|
||||
import { formatDateTimeToString } from '../../../../util/dates/dateFormat';
|
||||
import renderText from '../../../common/helpers/renderText';
|
||||
|
||||
import useLang from '../../../../hooks/useLang';
|
||||
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||
import useOldLang from '../../../../hooks/useOldLang';
|
||||
import usePrevious from '../../../../hooks/usePrevious';
|
||||
|
||||
import AnimatedIconFromSticker from '../../../common/AnimatedIconFromSticker';
|
||||
import Icon from '../../../common/icons/Icon';
|
||||
import StarIcon from '../../../common/icons/StarIcon';
|
||||
import SafeLink from '../../../common/SafeLink';
|
||||
@ -36,14 +43,19 @@ export type OwnProps = {
|
||||
|
||||
type StateProps = {
|
||||
peer?: ApiPeer;
|
||||
user?: ApiUser;
|
||||
canPlayAnimatedEmojis?: boolean;
|
||||
starGiftSticker?: ApiSticker;
|
||||
};
|
||||
|
||||
const StarsTransactionModal: FC<OwnProps & StateProps> = ({
|
||||
modal, peer,
|
||||
modal, peer, user, canPlayAnimatedEmojis, starGiftSticker,
|
||||
}) => {
|
||||
const { showNotification, openMediaViewer, closeStarsTransactionModal } = getActions();
|
||||
const lang = useOldLang();
|
||||
const oldLang = useOldLang();
|
||||
const lang = useLang();
|
||||
const { transaction } = modal || {};
|
||||
const isGift = transaction?.isGift;
|
||||
|
||||
const handleOpenMedia = useLastCallback(() => {
|
||||
const media = transaction?.extendedMedia;
|
||||
@ -55,6 +67,60 @@ const StarsTransactionModal: FC<OwnProps & StateProps> = ({
|
||||
});
|
||||
});
|
||||
|
||||
const animatedStickerData = useMemo(() => {
|
||||
if (!transaction) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return (
|
||||
<AnimatedIconFromSticker
|
||||
key={transaction.id}
|
||||
sticker={starGiftSticker}
|
||||
play={canPlayAnimatedEmojis}
|
||||
noLoop
|
||||
nonInteractive
|
||||
/>
|
||||
);
|
||||
}, [canPlayAnimatedEmojis, starGiftSticker, transaction]);
|
||||
|
||||
const giftEntryAboutText = useMemo(() => {
|
||||
const subtitleText = oldLang('lng_credits_box_history_entry_gift_in_about');
|
||||
const subtitleTextParts = subtitleText.split('{link}');
|
||||
|
||||
return (
|
||||
<>
|
||||
{subtitleTextParts[0]}
|
||||
<SafeLink
|
||||
url={oldLang('lng_credits_box_history_entry_gift_about_url')}
|
||||
text={oldLang('GiftStarsSubtitleLinkName')}
|
||||
>
|
||||
{renderText(oldLang('GiftStarsSubtitleLinkName'), ['simple_markdown'])}
|
||||
</SafeLink>
|
||||
{subtitleTextParts[1]}
|
||||
</>
|
||||
);
|
||||
}, [oldLang]);
|
||||
|
||||
const giftOutAboutText = useMemo(() => {
|
||||
return lang(
|
||||
'CreditsBoxHistoryEntryGiftOutAbout',
|
||||
{
|
||||
user: <strong>{user ? getUserFullName(user) : ''}</strong>,
|
||||
link: (
|
||||
<SafeLink
|
||||
url={oldLang('lng_credits_box_history_entry_gift_about_url')}
|
||||
text={oldLang('GiftStarsSubtitleLinkName')}
|
||||
>
|
||||
{renderText(oldLang('GiftStarsSubtitleLinkName'), ['simple_markdown'])}
|
||||
</SafeLink>
|
||||
),
|
||||
},
|
||||
{
|
||||
withNodes: true,
|
||||
},
|
||||
);
|
||||
}, [lang, user, oldLang]);
|
||||
|
||||
const starModalData = useMemo(() => {
|
||||
if (!transaction) {
|
||||
return undefined;
|
||||
@ -64,9 +130,9 @@ const StarsTransactionModal: FC<OwnProps & StateProps> = ({
|
||||
&& buildStarsTransactionCustomPeer(transaction.peer)) || undefined;
|
||||
|
||||
const peerId = transaction.peer?.type === 'peer' ? transaction.peer.id : undefined;
|
||||
const toName = transaction.peer && lang(getStarsPeerTitleKey(transaction.peer));
|
||||
const toName = transaction.peer && oldLang(getStarsPeerTitleKey(transaction.peer));
|
||||
|
||||
const title = transaction.title || (customPeer ? lang(customPeer.titleKey) : undefined);
|
||||
const title = transaction.title || (customPeer ? oldLang(customPeer.titleKey) : undefined);
|
||||
|
||||
const messageLink = peer && transaction.messageId
|
||||
? getMessageLink(peer, undefined, transaction.messageId) : undefined;
|
||||
@ -77,14 +143,14 @@ const StarsTransactionModal: FC<OwnProps & StateProps> = ({
|
||||
const areAllPhotos = media?.every((m) => !m.video);
|
||||
const areAllVideos = media?.every((m) => !m.photo);
|
||||
|
||||
const mediaText = areAllPhotos ? lang('Stars.Transfer.Photos', mediaAmount)
|
||||
: areAllVideos ? lang('Stars.Transfer.Videos', mediaAmount)
|
||||
: lang('Media', mediaAmount);
|
||||
const mediaText = areAllPhotos ? oldLang('Stars.Transfer.Photos', mediaAmount)
|
||||
: areAllVideos ? oldLang('Stars.Transfer.Videos', mediaAmount)
|
||||
: oldLang('Media', mediaAmount);
|
||||
|
||||
const description = transaction.description || (media ? mediaText : undefined);
|
||||
|
||||
const header = (
|
||||
<div className={styles.header}>
|
||||
<div className={buildClassName(styles.header, styles.starsHeader)}>
|
||||
{media && (
|
||||
<PaidMediaThumb
|
||||
className={buildClassName(styles.mediaPreview, 'transaction-media-preview')}
|
||||
@ -92,45 +158,57 @@ const StarsTransactionModal: FC<OwnProps & StateProps> = ({
|
||||
onClick={handleOpenMedia}
|
||||
/>
|
||||
)}
|
||||
<img
|
||||
className={buildClassName(styles.starsBackground, media && styles.mediaShift)}
|
||||
src={StarsBackground}
|
||||
alt=""
|
||||
draggable={false}
|
||||
/>
|
||||
{isGift ? animatedStickerData : (
|
||||
<img
|
||||
className={buildClassName(styles.starsBackground, media && styles.mediaShift)}
|
||||
src={StarsBackground}
|
||||
alt=""
|
||||
draggable={false}
|
||||
/>
|
||||
)}
|
||||
{title && <h1 className={styles.title}>{title}</h1>}
|
||||
{isGift && (
|
||||
<h1 className={buildClassName(styles.title, styles.starTitle)}>
|
||||
{transaction?.isMyGift ? oldLang('StarsGiftSent') : oldLang('StarsGiftReceived')}
|
||||
</h1>
|
||||
)}
|
||||
<p className={styles.description}>{description}</p>
|
||||
<p className={styles.amount}>
|
||||
<span className={buildClassName(styles.amount, transaction.stars < 0 ? styles.negative : styles.positive)}>
|
||||
{formatStarsTransactionAmount(transaction.stars)}
|
||||
</span>
|
||||
<StarIcon type="gold" size="big" />
|
||||
<StarIcon type="gold" size="middle" />
|
||||
</p>
|
||||
{isGift && (
|
||||
<span className={styles.subtitle}>
|
||||
{transaction?.isMyGift ? giftOutAboutText : giftEntryAboutText}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
const tableData: TableData = [];
|
||||
|
||||
tableData.push([
|
||||
lang(transaction.stars < 0 || transaction.isMyGift ? 'Stars.Transaction.To'
|
||||
oldLang(transaction.stars < 0 || transaction.isMyGift ? 'Stars.Transaction.To'
|
||||
: peerId ? 'Star.Transaction.From' : 'Stars.Transaction.Via'),
|
||||
peerId ? { chatId: peerId } : toName || '',
|
||||
]);
|
||||
|
||||
if (messageLink) {
|
||||
tableData.push([lang('Stars.Transaction.Media'), <SafeLink url={messageLink} text={messageLink} />]);
|
||||
tableData.push([oldLang('Stars.Transaction.Media'), <SafeLink url={messageLink} text={messageLink} />]);
|
||||
}
|
||||
|
||||
if (transaction.id) {
|
||||
tableData.push([
|
||||
lang('Stars.Transaction.Id'),
|
||||
oldLang('Stars.Transaction.Id'),
|
||||
(
|
||||
<span
|
||||
className={styles.tid}
|
||||
onClick={() => {
|
||||
copyTextToClipboard(transaction.id!);
|
||||
showNotification({
|
||||
message: lang('StarsTransactionIDCopied'),
|
||||
message: oldLang('StarsTransactionIDCopied'),
|
||||
});
|
||||
}}
|
||||
>
|
||||
@ -142,17 +220,17 @@ const StarsTransactionModal: FC<OwnProps & StateProps> = ({
|
||||
}
|
||||
|
||||
tableData.push([
|
||||
lang('Stars.Transaction.Date'),
|
||||
formatDateTimeToString(transaction.date * 1000, lang.code, true),
|
||||
oldLang('Stars.Transaction.Date'),
|
||||
formatDateTimeToString(transaction.date * 1000, oldLang.code, true),
|
||||
]);
|
||||
|
||||
const footerText = lang('lng_credits_box_out_about');
|
||||
const footerText = oldLang('lng_credits_box_out_about');
|
||||
const footerTextParts = footerText.split('{link}');
|
||||
|
||||
const footer = (
|
||||
<span className={styles.footer}>
|
||||
{footerTextParts[0]}
|
||||
<SafeLink url={lang('StarsTOSLink')} text={lang('lng_credits_summary_options_about_link')} />
|
||||
<SafeLink url={oldLang('StarsTOSLink')} text={oldLang('lng_credits_summary_options_about_link')} />
|
||||
{footerTextParts[1]}
|
||||
</span>
|
||||
);
|
||||
@ -163,7 +241,7 @@ const StarsTransactionModal: FC<OwnProps & StateProps> = ({
|
||||
footer,
|
||||
avatarPeer: !transaction.photo ? (peer || customPeer) : undefined,
|
||||
};
|
||||
}, [lang, transaction, peer]);
|
||||
}, [transaction, oldLang, peer, isGift, animatedStickerData, giftOutAboutText, giftEntryAboutText]);
|
||||
|
||||
const prevModalData = usePrevious(starModalData);
|
||||
const renderingModalData = prevModalData || starModalData;
|
||||
@ -173,12 +251,13 @@ const StarsTransactionModal: FC<OwnProps & StateProps> = ({
|
||||
isOpen={Boolean(transaction)}
|
||||
className={styles.modal}
|
||||
header={renderingModalData?.header}
|
||||
isGift={isGift}
|
||||
tableData={renderingModalData?.tableData}
|
||||
footer={renderingModalData?.footer}
|
||||
noHeaderImage={Boolean(transaction?.extendedMedia)}
|
||||
headerAvatarWebPhoto={transaction?.photo}
|
||||
headerAvatarPeer={renderingModalData?.avatarPeer}
|
||||
buttonText={lang('OK')}
|
||||
buttonText={oldLang('OK')}
|
||||
onClose={closeStarsTransactionModal}
|
||||
/>
|
||||
);
|
||||
@ -188,9 +267,16 @@ export default memo(withGlobal<OwnProps>(
|
||||
(global, { modal }): StateProps => {
|
||||
const peerId = modal?.transaction?.peer?.type === 'peer' && modal.transaction.peer.id;
|
||||
const peer = peerId ? selectPeer(global, peerId) : undefined;
|
||||
const user = peerId ? selectUser(global, peerId) : undefined;
|
||||
|
||||
const starCount = modal?.transaction.stars;
|
||||
const starGiftSticker = selectGiftStickerForStars(global, starCount);
|
||||
|
||||
return {
|
||||
peer,
|
||||
user,
|
||||
canPlayAnimatedEmojis: selectCanPlayAnimatedEmojis(global),
|
||||
starGiftSticker,
|
||||
};
|
||||
},
|
||||
)(StarsTransactionModal));
|
||||
|
||||
@ -583,7 +583,8 @@ addActionHandler('closePremiumGiftModal', (global, actions, payload): ActionRetu
|
||||
|
||||
addActionHandler('openStarsGiftModal', async (global, actions, payload): Promise<void> => {
|
||||
const {
|
||||
forUserId, tabId = getCurrentTabId(),
|
||||
forUserId,
|
||||
tabId = getCurrentTabId(),
|
||||
} = payload || {};
|
||||
|
||||
const starsGiftOptions = await callApi('getStarsGiftOptions', {});
|
||||
|
||||
@ -64,6 +64,23 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
||||
}
|
||||
}
|
||||
|
||||
if (inputInvoice?.type === 'stars') {
|
||||
if (!inputInvoice.stars) {
|
||||
return;
|
||||
}
|
||||
const starsModalState = selectTabState(global, tabId).starsGiftModal;
|
||||
|
||||
if (starsModalState && starsModalState.isOpen) {
|
||||
global = updateTabState(global, {
|
||||
starsGiftModal: {
|
||||
...starsModalState,
|
||||
isCompleted: true,
|
||||
},
|
||||
}, tabId);
|
||||
global = closeInvoice(global, tabId);
|
||||
}
|
||||
}
|
||||
|
||||
setGlobal(global);
|
||||
});
|
||||
|
||||
|
||||
@ -15,6 +15,12 @@ const MONTH_EMOTICON: Record<number, string> = {
|
||||
24: `${5}\u{FE0F}\u20E3`,
|
||||
};
|
||||
|
||||
const STAR_EMOTICON: Record<number, string> = {
|
||||
1000: `${2}\u{FE0F}\u20E3`,
|
||||
2500: `${3}\u{FE0F}\u20E3`,
|
||||
5000: `${4}\u{FE0F}\u20E3`,
|
||||
};
|
||||
|
||||
export function selectIsStickerFavorite<T extends GlobalState>(global: T, sticker: ApiSticker) {
|
||||
const { stickers } = global.stickers.favorite;
|
||||
return stickers && stickers.some(({ id }) => id === sticker.id);
|
||||
@ -156,3 +162,20 @@ export function selectGiftStickerForDuration<T extends GlobalState>(global: T, d
|
||||
const emoji = MONTH_EMOTICON[duration];
|
||||
return stickers.find((sticker) => sticker.emoji === emoji) || stickers[0];
|
||||
}
|
||||
|
||||
export function selectGiftStickerForStars<T extends GlobalState>(global: T, starCount?: number) {
|
||||
const stickers = global.premiumGifts?.stickers;
|
||||
|
||||
if (!stickers || !starCount) return undefined;
|
||||
|
||||
let emoji;
|
||||
if (starCount <= 1000) {
|
||||
emoji = STAR_EMOTICON[1000];
|
||||
} else if (starCount < 2500) {
|
||||
emoji = STAR_EMOTICON[2500];
|
||||
} else {
|
||||
emoji = STAR_EMOTICON[5000];
|
||||
}
|
||||
|
||||
return stickers.find((sticker) => sticker.emoji === emoji) || stickers[0];
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ import type {
|
||||
ApiSendMessageAction,
|
||||
ApiSession,
|
||||
ApiSessionData,
|
||||
ApiSponsoredMessage, ApiStarsGiftOption,
|
||||
ApiSponsoredMessage,
|
||||
ApiStarsTransaction,
|
||||
ApiStarTopupOption,
|
||||
ApiStealthMode,
|
||||
@ -725,7 +725,7 @@ export type TabState = {
|
||||
isCompleted?: boolean;
|
||||
isOpen?: boolean;
|
||||
forUserId?: string;
|
||||
starsGiftOptions?: ApiStarsGiftOption[];
|
||||
starsGiftOptions?: ApiStarTopupOption[];
|
||||
};
|
||||
|
||||
starsTransactionModal?: {
|
||||
@ -737,7 +737,7 @@ export type TabState = {
|
||||
isOpen?: boolean;
|
||||
forUserIds?: string[];
|
||||
gifts?: ApiPremiumGiftCodeOption[];
|
||||
starsGiftOptions?: ApiStarsGiftOption[];
|
||||
starsGiftOptions?: ApiStarTopupOption[];
|
||||
};
|
||||
|
||||
limitReachedModal?: {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user