Stars Transaction: Refactor modal (#4900)
This commit is contained in:
parent
a4b33eb43a
commit
8433012a88
@ -370,6 +370,7 @@ function buildAction(
|
||||
let isGiveaway: boolean | undefined;
|
||||
let isUnclaimed: boolean | undefined;
|
||||
let pluralValue: number | undefined;
|
||||
let transactionId: string | undefined;
|
||||
|
||||
let targetUserIds = 'users' in action
|
||||
? action.users && action.users.map((id) => buildApiPeerId(id, 'user'))
|
||||
@ -509,6 +510,7 @@ function buildAction(
|
||||
text = 'Notification.WebAppSentData';
|
||||
translationValues.push(action.text);
|
||||
} else if (action instanceof GramJs.MessageActionGiftPremium) {
|
||||
type = 'giftPremium';
|
||||
text = isOutgoing ? 'ActionGiftOutbound' : 'ActionGiftInbound';
|
||||
if (isOutgoing) {
|
||||
translationValues.push('%gift_payment_amount%');
|
||||
@ -561,6 +563,7 @@ function buildAction(
|
||||
text = 'BoostingGiveawayJustStarted';
|
||||
translationValues.push('%action_origin%');
|
||||
} else if (action instanceof GramJs.MessageActionGiftCode) {
|
||||
type = 'giftCode';
|
||||
text = isOutgoing ? 'ActionGiftOutbound' : 'BoostingReceivedGiftNoName';
|
||||
slug = action.slug;
|
||||
months = action.months;
|
||||
@ -621,7 +624,8 @@ function buildAction(
|
||||
translationValues.unshift('%action_origin%');
|
||||
}
|
||||
} else if (action instanceof GramJs.MessageActionGiftStars) {
|
||||
text = isOutgoing ? 'ActionGiftOutbound' : 'BoostingReceivedGiftNoName';
|
||||
type = 'giftStars';
|
||||
text = isOutgoing ? 'ActionGiftOutbound' : targetPeerId ? 'ActionGiftInbound' : 'BoostingReceivedGiftNoName';
|
||||
if (isOutgoing) {
|
||||
translationValues.push('%gift_payment_amount%');
|
||||
} else {
|
||||
@ -629,10 +633,20 @@ function buildAction(
|
||||
}
|
||||
if (targetPeerId) {
|
||||
targetUserIds.push(targetPeerId);
|
||||
targetChatId = targetPeerId;
|
||||
}
|
||||
|
||||
if (action.cryptoCurrency) {
|
||||
giftCryptoInfo = {
|
||||
currency: action.cryptoCurrency,
|
||||
amount: action.cryptoAmount!.toJSNumber(),
|
||||
};
|
||||
}
|
||||
|
||||
currency = action.currency;
|
||||
amount = action.amount.toJSNumber();
|
||||
stars = action.stars.toJSNumber();
|
||||
transactionId = action.transactionId;
|
||||
} else {
|
||||
text = 'ChatList.UnsupportedMessage';
|
||||
}
|
||||
@ -664,6 +678,7 @@ function buildAction(
|
||||
isTopicAction,
|
||||
isUnclaimed,
|
||||
pluralValue,
|
||||
transactionId,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -61,7 +61,10 @@ export function buildApiReceipt(receipt: GramJs.payments.TypePaymentReceipt): Ap
|
||||
return {
|
||||
type: 'stars',
|
||||
currency,
|
||||
botId: buildApiPeerId(botId, 'user'),
|
||||
peer: {
|
||||
type: 'peer',
|
||||
id: buildApiPeerId(botId, 'user'),
|
||||
},
|
||||
date,
|
||||
text,
|
||||
title,
|
||||
@ -426,7 +429,7 @@ export function buildApiStarsTransactionPeer(peer: GramJs.TypeStarsTransactionPe
|
||||
|
||||
export function buildApiStarsTransaction(transaction: GramJs.StarsTransaction): ApiStarsTransaction {
|
||||
const {
|
||||
date, id, peer, stars, description, photo, title, refund, extendedMedia, failed, msgId, pending,
|
||||
date, id, peer, stars, description, photo, title, refund, extendedMedia, failed, msgId, pending, gift,
|
||||
} = transaction;
|
||||
|
||||
if (photo) {
|
||||
@ -448,6 +451,7 @@ export function buildApiStarsTransaction(transaction: GramJs.StarsTransaction):
|
||||
hasFailed: failed,
|
||||
isPending: pending,
|
||||
messageId: msgId,
|
||||
isGift: gift,
|
||||
extendedMedia: boughtExtendedMedia,
|
||||
};
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ export {
|
||||
validateRequestedInfo, sendPaymentForm, getPaymentForm, getReceipt, fetchPremiumPromo, fetchTemporaryPaymentPassword,
|
||||
applyBoost, fetchBoostList, fetchBoostStatus, fetchGiveawayInfo, fetchMyBoosts, applyGiftCode, checkGiftCode,
|
||||
getPremiumGiftCodeOptions, launchPrepaidGiveaway, fetchStarsStatus, fetchStarsTopupOptions, fetchStarsTransactions,
|
||||
sendStarPaymentForm, getStarsGiftOptions,
|
||||
sendStarPaymentForm, getStarsGiftOptions, fetchStarsTransactionById,
|
||||
} from './payments';
|
||||
|
||||
export * from './fragment';
|
||||
|
||||
@ -459,16 +459,19 @@ export async function fetchStarsStatus() {
|
||||
}
|
||||
|
||||
export async function fetchStarsTransactions({
|
||||
peer,
|
||||
offset,
|
||||
isInbound,
|
||||
isOutbound,
|
||||
}: {
|
||||
peer?: ApiPeer;
|
||||
offset?: string;
|
||||
isInbound?: true;
|
||||
isOutbound?: true;
|
||||
}) {
|
||||
const inputPeer = peer ? buildInputPeer(peer.id, peer.accessHash) : new GramJs.InputPeerSelf();
|
||||
const result = await invokeRequest(new GramJs.payments.GetStarsTransactions({
|
||||
peer: new GramJs.InputPeerSelf(),
|
||||
peer: inputPeer,
|
||||
offset,
|
||||
inbound: isInbound,
|
||||
outbound: isOutbound,
|
||||
@ -490,6 +493,34 @@ export async function fetchStarsTransactions({
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchStarsTransactionById({
|
||||
id, peer,
|
||||
}: {
|
||||
id: string;
|
||||
peer?: ApiPeer;
|
||||
}) {
|
||||
const inputPeer = peer ? buildInputPeer(peer.id, peer.accessHash) : new GramJs.InputPeerSelf();
|
||||
const result = await invokeRequest(new GramJs.payments.GetStarsTransactionsByID({
|
||||
peer: inputPeer,
|
||||
id: [new GramJs.InputStarsTransaction({
|
||||
id,
|
||||
})],
|
||||
}));
|
||||
|
||||
if (!result?.history?.[0]) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const users = result.users.map(buildApiUser).filter(Boolean);
|
||||
const chats = result.chats.map((c) => buildApiChatFromPreview(c)).filter(Boolean);
|
||||
|
||||
return {
|
||||
users,
|
||||
chats,
|
||||
transaction: buildApiStarsTransaction(result.history[0]),
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchStarsTopupOptions() {
|
||||
const result = await invokeRequest(new GramJs.payments.GetStarsTopupOptions());
|
||||
|
||||
|
||||
@ -397,6 +397,9 @@ export interface ApiAction {
|
||||
| 'joinedChannel'
|
||||
| 'chatBoost'
|
||||
| 'receipt'
|
||||
| 'giftStars'
|
||||
| 'giftPremium'
|
||||
| 'giftCode'
|
||||
| 'other';
|
||||
photo?: ApiPhoto;
|
||||
amount?: number;
|
||||
|
||||
@ -3,7 +3,7 @@ import type { ApiInvoiceContainer } from '../../types';
|
||||
import type { ApiWebDocument } from './bots';
|
||||
import type { ApiChat } from './chats';
|
||||
import type {
|
||||
ApiDocument, ApiMessageEntity, ApiPaymentCredentials, BoughtPaidMedia, MediaContent,
|
||||
ApiDocument, ApiMessageEntity, ApiPaymentCredentials, BoughtPaidMedia,
|
||||
} from './messages';
|
||||
import type { PrepaidGiveaway, StatisticsOverviewPercentage } from './statistics';
|
||||
import type { ApiUser } from './users';
|
||||
@ -63,8 +63,7 @@ export interface ApiLabeledPrice {
|
||||
|
||||
export interface ApiReceiptStars {
|
||||
type: 'stars';
|
||||
botId?: string;
|
||||
peer?: ApiStarsTransactionPeer;
|
||||
peer: ApiStarsTransactionPeer;
|
||||
date: number;
|
||||
title?: string;
|
||||
text?: string;
|
||||
@ -273,18 +272,20 @@ export type ApiStarsTransactionPeer =
|
||||
| ApiStarsTransactionPeerPeer;
|
||||
|
||||
export interface ApiStarsTransaction {
|
||||
id: string;
|
||||
id?: string;
|
||||
peer: ApiStarsTransactionPeer;
|
||||
messageId?: number;
|
||||
stars: number;
|
||||
isRefund?: true;
|
||||
isGift?: true;
|
||||
isMyGift?: true; // Used only for outgoing star gift messages
|
||||
hasFailed?: true;
|
||||
isPending?: true;
|
||||
date: number;
|
||||
title?: string;
|
||||
description?: string;
|
||||
photo?: ApiWebDocument;
|
||||
extendedMedia?: MediaContent[];
|
||||
extendedMedia?: BoughtPaidMedia[];
|
||||
}
|
||||
|
||||
export interface ApiStarTopupOption {
|
||||
|
||||
@ -25,10 +25,10 @@ export { default as PremiumLimitReachedModal } from '../components/main/premium/
|
||||
export { default as StatusPickerMenu } from '../components/left/main/StatusPickerMenu';
|
||||
export { default as BoostModal } from '../components/modals/boost/BoostModal';
|
||||
export { default as GiftCodeModal } from '../components/modals/giftcode/GiftCodeModal';
|
||||
export { default as StarGiftInfoModal } from '../components/modals/stars/StarGiftInfoModal';
|
||||
export { default as ChatlistModal } from '../components/modals/chatlist/ChatlistModal';
|
||||
export { default as StarsBalanceModal } from '../components/modals/stars/StarsBalanceModal';
|
||||
export { default as StarPaymentModal } from '../components/modals/stars/StarsPaymentModal';
|
||||
export { default as StarsTransactionInfoModal } from '../components/modals/stars/transaction/StarsTransactionModal';
|
||||
|
||||
export { default as AboutAdsModal } from '../components/common/AboutAdsModal';
|
||||
export { default as AboutMonetizationModal } from '../components/common/AboutMonetizationModal';
|
||||
|
||||
@ -26,6 +26,7 @@ import {
|
||||
isUserId,
|
||||
} from '../../global/helpers';
|
||||
import buildClassName, { createClassNameBuilder } from '../../util/buildClassName';
|
||||
import buildStyle from '../../util/buildStyle';
|
||||
import { getFirstLetters } from '../../util/textFormat';
|
||||
import { getPeerColorClass } from './helpers/peerColor';
|
||||
import renderText from './helpers/renderText';
|
||||
@ -225,6 +226,7 @@ const Avatar: FC<OwnProps> = ({
|
||||
const isRoundedRect = (isCustomPeer && peer.isAvatarSquare)
|
||||
|| (isForum && !((withStory || withStorySolid) && realPeer?.hasStories));
|
||||
const isPremiumGradient = isCustomPeer && peer.withPremiumGradient;
|
||||
const customColor = isCustomPeer && peer.customPeerAvatarColor;
|
||||
|
||||
const fullClassName = buildClassName(
|
||||
`Avatar size-${size}`,
|
||||
@ -273,6 +275,7 @@ const Avatar: FC<OwnProps> = ({
|
||||
data-peer-id={realPeer?.id}
|
||||
data-test-sender-id={IS_TEST ? realPeer?.id : undefined}
|
||||
aria-label={typeof content === 'string' ? author : undefined}
|
||||
style={buildStyle(customColor && `--color-user: ${customColor}`)}
|
||||
onClick={handleClick}
|
||||
onMouseDown={handleMouseDown}
|
||||
>
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import '../../global/actions/all';
|
||||
|
||||
import type { FC } from '../../lib/teact/teact';
|
||||
import React, {
|
||||
memo, useEffect, useLayoutEffect,
|
||||
useRef, useState,
|
||||
@ -9,7 +8,6 @@ import { addExtraClass } from '../../lib/teact/teact-dom';
|
||||
import { getActions, getGlobal, withGlobal } from '../../global';
|
||||
|
||||
import type {
|
||||
ApiChat,
|
||||
ApiChatFolder,
|
||||
ApiMessage,
|
||||
ApiUser,
|
||||
@ -74,7 +72,6 @@ import ReactionPicker from '../middle/message/reactions/ReactionPicker.async';
|
||||
import MessageListHistoryHandler from '../middle/MessageListHistoryHandler';
|
||||
import MiddleColumn from '../middle/MiddleColumn';
|
||||
import ModalContainer from '../modals/ModalContainer';
|
||||
import StarGiftInfoModal from '../modals/stars/StarGiftInfoModal';
|
||||
import PaymentModal from '../payment/PaymentModal.async';
|
||||
import ReceiptModal from '../payment/ReceiptModal.async';
|
||||
import RightColumn from '../right/RightColumn';
|
||||
@ -106,7 +103,6 @@ export interface OwnProps {
|
||||
|
||||
type StateProps = {
|
||||
isMasterTab?: boolean;
|
||||
chat?: ApiChat;
|
||||
currentUserId?: string;
|
||||
isLeftColumnOpen: boolean;
|
||||
isMiddleColumnOpen: boolean;
|
||||
@ -144,12 +140,10 @@ type StateProps = {
|
||||
isPaymentModalOpen?: boolean;
|
||||
isReceiptModalOpen?: boolean;
|
||||
isReactionPickerOpen: boolean;
|
||||
isAppendModalOpen?: boolean;
|
||||
isGiveawayModalOpen?: boolean;
|
||||
isDeleteMessageModalOpen?: boolean;
|
||||
isPremiumGiftingPickerModal?: boolean;
|
||||
isStarsGiftingPickerModal?: boolean;
|
||||
isStarGiftInfoModal?: boolean;
|
||||
isCurrentUserPremium?: boolean;
|
||||
noRightColumnAnimation?: boolean;
|
||||
withInterfaceAnimations?: boolean;
|
||||
@ -162,7 +156,7 @@ const CALL_BUNDLE_LOADING_DELAY_MS = 5000; // 5 sec
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
let DEBUG_isLogged = false;
|
||||
|
||||
const Main: FC<OwnProps & StateProps> = ({
|
||||
const Main = ({
|
||||
isMobile,
|
||||
isLeftColumnOpen,
|
||||
isMiddleColumnOpen,
|
||||
@ -201,7 +195,6 @@ const Main: FC<OwnProps & StateProps> = ({
|
||||
isDeleteMessageModalOpen,
|
||||
isPremiumGiftingPickerModal,
|
||||
isStarsGiftingPickerModal,
|
||||
isStarGiftInfoModal,
|
||||
isPaymentModalOpen,
|
||||
isReceiptModalOpen,
|
||||
isReactionPickerOpen,
|
||||
@ -211,7 +204,7 @@ const Main: FC<OwnProps & StateProps> = ({
|
||||
noRightColumnAnimation,
|
||||
isSynced,
|
||||
currentUserId,
|
||||
}) => {
|
||||
}: OwnProps & StateProps) => {
|
||||
const {
|
||||
initMain,
|
||||
loadAnimatedEmojis,
|
||||
@ -584,7 +577,6 @@ const Main: FC<OwnProps & StateProps> = ({
|
||||
{isGiveawayModalOpen && <GiveawayModal isOpen={isGiveawayModalOpen} />}
|
||||
{isPremiumGiftingPickerModal && <PremiumGiftingPickerModal isOpen={isPremiumGiftingPickerModal} />}
|
||||
{isStarsGiftingPickerModal && <StarsGiftingPickerModal isOpen={isStarsGiftingPickerModal} />}
|
||||
{isStarGiftInfoModal && <StarGiftInfoModal isOpen={isStarGiftInfoModal} />}
|
||||
<PremiumLimitReachedModal limit={limitReached} />
|
||||
<PaymentModal isOpen={isPaymentModalOpen} onClose={closePaymentModal} />
|
||||
<ReceiptModal isOpen={isReceiptModalOpen} onClose={clearReceipt} />
|
||||
@ -627,7 +619,6 @@ export default memo(withGlobal<OwnProps>(
|
||||
deleteMessageModal,
|
||||
giftingModal,
|
||||
starsGiftingModal,
|
||||
starGiftInfoModal,
|
||||
isMasterTab,
|
||||
payment,
|
||||
limitReachedModal,
|
||||
@ -685,7 +676,6 @@ export default memo(withGlobal<OwnProps>(
|
||||
isDeleteMessageModalOpen: Boolean(deleteMessageModal),
|
||||
isPremiumGiftingPickerModal: giftingModal?.isOpen,
|
||||
isStarsGiftingPickerModal: starsGiftingModal?.isOpen,
|
||||
isStarGiftInfoModal: starGiftInfoModal?.isOpen,
|
||||
limitReached: limitReachedModal?.limit,
|
||||
isPaymentModalOpen: payment.isPaymentModalOpen,
|
||||
isReceiptModalOpen: Boolean(payment.receipt),
|
||||
|
||||
@ -13,7 +13,7 @@ import type { FocusDirection, ThreadId } from '../../types';
|
||||
import type { PinnedIntersectionChangedCallback } from './hooks/usePinnedMessage';
|
||||
|
||||
import {
|
||||
getChatTitle, getMessageHtmlId, getSenderTitle, isJoinedChannelMessage,
|
||||
getChatTitle, getMessageHtmlId, isJoinedChannelMessage,
|
||||
} from '../../global/helpers';
|
||||
import { getMessageReplyInfo } from '../../global/helpers/replies';
|
||||
import {
|
||||
@ -35,7 +35,6 @@ import useContextMenuHandlers from '../../hooks/useContextMenuHandlers';
|
||||
import useEnsureMessage from '../../hooks/useEnsureMessage';
|
||||
import useFlag from '../../hooks/useFlag';
|
||||
import { useIsIntersecting, useOnIntersect } from '../../hooks/useIntersectionObserver';
|
||||
import useLang from '../../hooks/useLang';
|
||||
import useOldLang from '../../hooks/useOldLang';
|
||||
import useShowTransition from '../../hooks/useShowTransition';
|
||||
import useFocusMessage from './message/hooks/useFocusMessage';
|
||||
@ -104,11 +103,10 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
|
||||
onPinnedIntersectionChange,
|
||||
}) => {
|
||||
const {
|
||||
openPremiumModal, requestConfetti, checkGiftCode, getReceipt, openStarGiftInfoModal,
|
||||
openPremiumModal, requestConfetti, checkGiftCode, getReceipt, openStarsTransactionFromGift,
|
||||
} = getActions();
|
||||
|
||||
const oldLang = useOldLang();
|
||||
const lang = useLang();
|
||||
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
@ -131,11 +129,11 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
|
||||
|
||||
const noAppearanceAnimation = appearanceOrder <= 0;
|
||||
const [isShown, markShown] = useFlag(noAppearanceAnimation);
|
||||
const isGift = Boolean(message.content.action?.text.startsWith('ActionGift'));
|
||||
const isGiftCode = Boolean(message.content.action?.text.startsWith('BoostingReceivedGift'));
|
||||
const isPremiumGift = message.content.action?.type === 'giftPremium';
|
||||
const isGiftCode = message.content.action?.type === 'giftCode';
|
||||
const isSuggestedAvatar = message.content.action?.type === 'suggestProfilePhoto' && message.content.action!.photo;
|
||||
const isJoinedMessage = isJoinedChannelMessage(message);
|
||||
const hasStars = Boolean(message.content.action?.stars);
|
||||
const isStarsGift = message.content.action?.type === 'giftStars';
|
||||
|
||||
useEffect(() => {
|
||||
if (noAppearanceAnimation) {
|
||||
@ -149,7 +147,7 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
|
||||
|
||||
const shouldShowConfettiRef = useRef((() => {
|
||||
const isUnread = memoFirstUnreadIdRef?.current && message.id >= memoFirstUnreadIdRef.current;
|
||||
return isGift && !message.isOutgoing && isUnread;
|
||||
return isPremiumGift && !message.isOutgoing && isUnread;
|
||||
})());
|
||||
|
||||
useEffect(() => {
|
||||
@ -201,10 +199,9 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
|
||||
};
|
||||
|
||||
const handleStarGiftClick = () => {
|
||||
openStarGiftInfoModal({
|
||||
toUserId: targetUserIds?.[0],
|
||||
stars: message.content.action!.stars,
|
||||
date: message.date,
|
||||
openStarsTransactionFromGift({
|
||||
chatId: message.chatId,
|
||||
messageId: message.id,
|
||||
});
|
||||
};
|
||||
|
||||
@ -245,10 +242,10 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
|
||||
function renderGift() {
|
||||
return (
|
||||
<span
|
||||
className="action-message-gift action-message-stars-gift"
|
||||
className="action-message-gift"
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
onClick={hasStars ? handleStarGiftClick : handlePremiumGiftClick}
|
||||
onClick={handlePremiumGiftClick}
|
||||
>
|
||||
<AnimatedIconFromSticker
|
||||
key={message.id}
|
||||
@ -257,11 +254,9 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
|
||||
noLoop
|
||||
nonInteractive
|
||||
/>
|
||||
<strong>{hasStars ? oldLang('Stars', message.content.action?.stars)
|
||||
: oldLang('ActionGiftPremiumTitle')}
|
||||
</strong>
|
||||
<span>{hasStars ? oldLang('ActionGiftStarsSubtitleYou')
|
||||
: oldLang('ActionGiftPremiumSubtitle', oldLang('Months', message.content.action?.months, 'i'))}
|
||||
<strong>{oldLang('ActionGiftPremiumTitle')}</strong>
|
||||
<span>
|
||||
{oldLang('ActionGiftPremiumSubtitle', oldLang('Months', message.content.action?.months, 'i'))}
|
||||
</span>
|
||||
|
||||
<span className="action-message-button">{oldLang('ActionGiftPremiumView')}</span>
|
||||
@ -277,7 +272,7 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
|
||||
className="action-message-gift action-message-gift-code"
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
onClick={hasStars ? handleStarGiftClick : handleGiftCodeClick}
|
||||
onClick={handleGiftCodeClick}
|
||||
>
|
||||
<AnimatedIconFromSticker
|
||||
key={message.id}
|
||||
@ -286,34 +281,57 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
|
||||
noLoop
|
||||
nonInteractive
|
||||
/>
|
||||
<strong>{hasStars ? oldLang('Stars', message.content.action?.stars)
|
||||
: oldLang(isUnclaimed ? 'BoostingUnclaimedPrize' : 'BoostingCongratulations')}
|
||||
<strong>
|
||||
{oldLang(isUnclaimed ? 'BoostingUnclaimedPrize' : 'BoostingCongratulations')}
|
||||
</strong>
|
||||
<span className="action-message-subtitle">
|
||||
{hasStars ? lang('GiftStarsOutgoing', {
|
||||
user: (
|
||||
<b>
|
||||
{senderUser && renderText(getSenderTitle(oldLang, senderUser) || '', ['simple_markdown'])}
|
||||
</b>
|
||||
),
|
||||
}, {
|
||||
withNodes: true,
|
||||
}) : targetChat && renderText(oldLang(isFromGiveaway ? 'BoostingReceivedGiftFrom' : isUnclaimed
|
||||
{targetChat && renderText(oldLang(isFromGiveaway ? 'BoostingReceivedGiftFrom' : isUnclaimed
|
||||
? 'BoostingReceivedPrizeFrom' : 'BoostingYouHaveUnclaimedPrize',
|
||||
getChatTitle(oldLang, targetChat)),
|
||||
['simple_markdown'])}
|
||||
</span>
|
||||
{!hasStars && (
|
||||
<span className="action-message-subtitle">
|
||||
{renderText(oldLang(
|
||||
'BoostingUnclaimedPrizeDuration',
|
||||
oldLang('Months', message.content.action?.months, 'i'),
|
||||
), ['simple_markdown'])}
|
||||
</span>
|
||||
)}
|
||||
<span className="action-message-subtitle">
|
||||
{renderText(oldLang(
|
||||
'BoostingUnclaimedPrizeDuration',
|
||||
oldLang('Months', message.content.action?.months, 'i'),
|
||||
), ['simple_markdown'])}
|
||||
</span>
|
||||
|
||||
<span className="action-message-button">{
|
||||
oldLang(hasStars ? 'ActionGiftPremiumView' : 'BoostingReceivedGiftOpenBtn')
|
||||
oldLang('BoostingReceivedGiftOpenBtn')
|
||||
}
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
function renderStarsGift() {
|
||||
return (
|
||||
<span
|
||||
className="action-message-gift action-message-gift-code"
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
onClick={handleStarGiftClick}
|
||||
>
|
||||
<AnimatedIconFromSticker
|
||||
key={message.id}
|
||||
sticker={premiumGiftSticker}
|
||||
play={canPlayAnimatedEmojis}
|
||||
noLoop
|
||||
nonInteractive
|
||||
/>
|
||||
<strong>
|
||||
{oldLang('Stars', message.content.action!.stars)}
|
||||
</strong>
|
||||
<span className="action-message-subtitle">
|
||||
{renderText(
|
||||
oldLang(!message.isOutgoing
|
||||
? 'ActionGiftStarsSubtitleYou' : 'ActionGiftStarsSubtitle', getChatTitle(oldLang, targetChat!)),
|
||||
['simple_markdown'],
|
||||
)}
|
||||
</span>
|
||||
<span className="action-message-button">{
|
||||
oldLang('ActionGiftPremiumView')
|
||||
}
|
||||
</span>
|
||||
</span>
|
||||
@ -323,7 +341,7 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
|
||||
const className = buildClassName(
|
||||
'ActionMessage message-list-item',
|
||||
isFocused && !noFocusHighlight && 'focused',
|
||||
(isGift || isSuggestedAvatar) && 'centered-action',
|
||||
(isPremiumGift || isSuggestedAvatar) && 'centered-action',
|
||||
isContextMenuShown && 'has-menu-open',
|
||||
isLastInList && 'last-in-list',
|
||||
transitionClassNames,
|
||||
@ -342,8 +360,9 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
|
||||
{!isSuggestedAvatar && !isGiftCode && !isJoinedMessage && (
|
||||
<span className="action-message-content" onClick={handleClick}>{renderContent()}</span>
|
||||
)}
|
||||
{isGift && renderGift()}
|
||||
{isPremiumGift && renderGift()}
|
||||
{isGiftCode && renderGiftCode()}
|
||||
{isStarsGift && renderStarsGift()}
|
||||
{isSuggestedAvatar && (
|
||||
<ActionMessageSuggestedAvatar message={message} renderContent={renderContent} />
|
||||
)}
|
||||
|
||||
@ -17,6 +17,7 @@ import OneTimeMediaModal from './oneTimeMedia/OneTimeMediaModal.async';
|
||||
import ReportAdModal from './reportAd/ReportAdModal.async';
|
||||
import StarsBalanceModal from './stars/StarsBalanceModal.async';
|
||||
import StarsPaymentModal from './stars/StarsPaymentModal.async';
|
||||
import StarsTransactionInfoModal from './stars/transaction/StarsTransactionModal.async';
|
||||
import UrlAuthModal from './urlAuth/UrlAuthModal.async';
|
||||
import WebAppModal from './webApp/WebAppModal.async';
|
||||
|
||||
@ -34,7 +35,8 @@ type ModalKey = keyof Pick<TabState,
|
||||
'reportAdModal' |
|
||||
'starsBalanceModal' |
|
||||
'isStarPaymentModalOpen' |
|
||||
'webApp'
|
||||
'webApp' |
|
||||
'starsTransactionModal'
|
||||
>;
|
||||
|
||||
type StateProps = {
|
||||
@ -63,6 +65,7 @@ const MODALS: ModalRegistry = {
|
||||
mapModal: MapModal,
|
||||
isStarPaymentModalOpen: StarsPaymentModal,
|
||||
starsBalanceModal: StarsBalanceModal,
|
||||
starsTransactionModal: StarsTransactionInfoModal,
|
||||
};
|
||||
const MODAL_KEYS = Object.keys(MODALS) as ModalKey[];
|
||||
const MODAL_ENTRIES = Object.entries(MODALS) as Entries<ModalRegistry>;
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import React from '../../../lib/teact/teact';
|
||||
|
||||
import type { OwnProps } from './StarGiftInfoModal';
|
||||
|
||||
import { Bundles } from '../../../util/moduleLoader';
|
||||
|
||||
import useModuleLoader from '../../../hooks/useModuleLoader';
|
||||
|
||||
const StarGiftInfoModalAsync: FC<OwnProps> = (props) => {
|
||||
const { isOpen } = props;
|
||||
const StarGiftInfoModal = useModuleLoader(Bundles.Extra, 'StarGiftInfoModal', !isOpen);
|
||||
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
return StarGiftInfoModal ? <StarGiftInfoModal {...props} /> : undefined;
|
||||
};
|
||||
|
||||
export default StarGiftInfoModalAsync;
|
||||
@ -1,32 +0,0 @@
|
||||
@use '../../../styles/mixins';
|
||||
|
||||
.centered {
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
padding: 0.5rem;
|
||||
position: relative;
|
||||
|
||||
@include mixins.adapt-padding-to-scrollbar(0.5rem);
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.starTitle {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin: 1rem 0;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
@ -1,150 +0,0 @@
|
||||
import React, { memo, useMemo } from '../../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
import type { ApiPeer } from '../../../api/types';
|
||||
|
||||
import { getSenderTitle } from '../../../global/helpers';
|
||||
import { selectTabState, selectUser } from '../../../global/selectors';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
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 StarIcon from '../../common/icons/StarIcon';
|
||||
import SafeLink from '../../common/SafeLink';
|
||||
import TableInfoModal, { type TableData } from '../common/TableInfoModal';
|
||||
|
||||
import styles from './StarGiftInfoModal.module.scss';
|
||||
|
||||
import StarLogo from '../../../assets/icons/StarLogo.svg';
|
||||
import StarsBackground from '../../../assets/stars-bg.png';
|
||||
|
||||
export type OwnProps = {
|
||||
isOpen?: boolean;
|
||||
};
|
||||
|
||||
export type StateProps = {
|
||||
stars?: number;
|
||||
user?: ApiPeer;
|
||||
date?: number;
|
||||
};
|
||||
|
||||
const StarGiftInfoModal = ({
|
||||
isOpen,
|
||||
stars,
|
||||
user,
|
||||
date,
|
||||
}: OwnProps & StateProps) => {
|
||||
const {
|
||||
closeStarGiftInfoModal,
|
||||
} = getActions();
|
||||
const oldLang = useOldLang();
|
||||
const lang = useLang();
|
||||
|
||||
const infoText = useMemo(() => {
|
||||
const linkText = oldLang('GiftStarsSubtitleLinkName');
|
||||
|
||||
return lang('CreditsBoxHistoryEntryGiftOutAbout',
|
||||
{
|
||||
user: (
|
||||
<b>
|
||||
{user && renderText(getSenderTitle(oldLang, user) || '', ['simple_markdown'])}
|
||||
</b>
|
||||
),
|
||||
link: (
|
||||
<SafeLink
|
||||
url={oldLang('lng_paid_about_link_url')}
|
||||
text={linkText}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
withNodes: true,
|
||||
});
|
||||
}, [lang, oldLang, user]);
|
||||
|
||||
const footerText = useMemo(() => {
|
||||
const linkText = oldLang('lng_payments_terms_link');
|
||||
return lang('CreditsBoxOutAbout', {
|
||||
link: (
|
||||
<SafeLink
|
||||
url={oldLang('StarsTOSLink')}
|
||||
text={linkText}
|
||||
/>
|
||||
),
|
||||
}, {
|
||||
withNodes: true,
|
||||
});
|
||||
}, [lang, oldLang]);
|
||||
|
||||
const handleButtonClick = useLastCallback(() => {
|
||||
closeStarGiftInfoModal();
|
||||
});
|
||||
|
||||
const modalData = useMemo(() => {
|
||||
if (!isOpen) return undefined;
|
||||
|
||||
const header = (
|
||||
<>
|
||||
<h2 className={buildClassName(styles.starTitle, styles.centered)}>{oldLang('StarsGiftSent')}</h2>
|
||||
<div className={styles.info}>
|
||||
<p className={buildClassName(styles.starTitle, styles.centered)}>{stars}</p>
|
||||
<StarIcon type="gold" size="middle" />
|
||||
</div>
|
||||
<p className={styles.centered}>{infoText}</p>
|
||||
</>
|
||||
);
|
||||
|
||||
const tableData = [
|
||||
[oldLang('Recipient'), user ? { chatId: user.id } : oldLang('BoostingNoRecipient')],
|
||||
[oldLang('BoostingDate'), formatDateTimeToString(date! * 1000, lang.code, true)],
|
||||
] satisfies TableData;
|
||||
|
||||
const footer = (
|
||||
<span className={buildClassName(styles.footer, styles.centered)}>
|
||||
{footerText}
|
||||
</span>
|
||||
);
|
||||
|
||||
return {
|
||||
header,
|
||||
tableData,
|
||||
footer,
|
||||
};
|
||||
}, [isOpen, oldLang, stars, infoText, user, date, lang.code, footerText]);
|
||||
|
||||
if (!modalData) return undefined;
|
||||
|
||||
return (
|
||||
<TableInfoModal
|
||||
isOpen={isOpen}
|
||||
headerImageUrl={StarLogo}
|
||||
logoBackground={StarsBackground}
|
||||
tableData={modalData.tableData}
|
||||
header={modalData.header}
|
||||
footer={modalData.footer}
|
||||
buttonText={lang('Close')}
|
||||
onButtonClick={handleButtonClick}
|
||||
onClose={closeStarGiftInfoModal}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(withGlobal<OwnProps>(
|
||||
(global): StateProps => {
|
||||
const {
|
||||
starGiftInfoModal,
|
||||
} = selectTabState(global);
|
||||
const toUserId = starGiftInfoModal?.toUserId;
|
||||
const user = toUserId ? selectUser(global, toUserId) : undefined;
|
||||
|
||||
return {
|
||||
stars: starGiftInfoModal?.stars,
|
||||
user,
|
||||
date: starGiftInfoModal?.date,
|
||||
};
|
||||
},
|
||||
)(StarGiftInfoModal));
|
||||
@ -24,8 +24,8 @@ import Modal from '../../ui/Modal';
|
||||
import TabList, { type TabWithProperties } from '../../ui/TabList';
|
||||
import Transition from '../../ui/Transition';
|
||||
import BalanceBlock from './BalanceBlock';
|
||||
import TransactionItem from './StarsTransactionItem';
|
||||
import StarTopupOptionList from './StarTopupOptionList';
|
||||
import TransactionItem from './transaction/StarsTransactionItem';
|
||||
|
||||
import styles from './StarsBalanceModal.module.scss';
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@ import StarIcon from '../../common/icons/StarIcon';
|
||||
import Button from '../../ui/Button';
|
||||
import Modal from '../../ui/Modal';
|
||||
import BalanceBlock from './BalanceBlock';
|
||||
import PaidMediaThumb from './PaidMediaThumb';
|
||||
import PaidMediaThumb from './transaction/PaidMediaThumb';
|
||||
|
||||
import styles from './StarsBalanceModal.module.scss';
|
||||
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import React, { memo } from '../../../lib/teact/teact';
|
||||
import React, { memo } from '../../../../lib/teact/teact';
|
||||
|
||||
import type { ApiMediaExtendedPreview, BoughtPaidMedia } from '../../../api/types';
|
||||
import type { ApiMediaExtendedPreview, BoughtPaidMedia } from '../../../../api/types';
|
||||
|
||||
import { getMediaHash, getMediaThumbUri } from '../../../global/helpers';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import { getMediaHash, getMediaThumbUri } from '../../../../global/helpers';
|
||||
import buildClassName from '../../../../util/buildClassName';
|
||||
|
||||
import useMedia from '../../../hooks/useMedia';
|
||||
import useMedia from '../../../../hooks/useMedia';
|
||||
|
||||
import Icon from '../../common/icons/Icon';
|
||||
import MediaSpoiler from '../../common/MediaSpoiler';
|
||||
import Icon from '../../../common/icons/Icon';
|
||||
import MediaSpoiler from '../../../common/MediaSpoiler';
|
||||
|
||||
import styles from './PaidMediaThumb.module.scss';
|
||||
|
||||
@ -1,26 +1,26 @@
|
||||
import React, { memo, useMemo } from '../../../lib/teact/teact';
|
||||
import { getActions } from '../../../global';
|
||||
import React, { memo, useMemo } from '../../../../lib/teact/teact';
|
||||
import { getActions } from '../../../../global';
|
||||
|
||||
import type {
|
||||
ApiPeer,
|
||||
ApiStarsTransaction,
|
||||
} from '../../../api/types';
|
||||
import type { GlobalState } from '../../../global/types';
|
||||
import type { CustomPeer } from '../../../types';
|
||||
} from '../../../../api/types';
|
||||
import type { GlobalState } from '../../../../global/types';
|
||||
import type { CustomPeer } from '../../../../types';
|
||||
|
||||
import { getSenderTitle } from '../../../global/helpers';
|
||||
import { buildStarsTransactionCustomPeer, formatStarsTransactionAmount } from '../../../global/helpers/payments';
|
||||
import { selectPeer } from '../../../global/selectors';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import { formatDateTimeToString } from '../../../util/dates/dateFormat';
|
||||
import { CUSTOM_PEER_PREMIUM } from '../../../util/objects/customPeer';
|
||||
import { getSenderTitle } from '../../../../global/helpers';
|
||||
import { buildStarsTransactionCustomPeer, formatStarsTransactionAmount } from '../../../../global/helpers/payments';
|
||||
import { selectPeer } from '../../../../global/selectors';
|
||||
import buildClassName from '../../../../util/buildClassName';
|
||||
import { formatDateTimeToString } from '../../../../util/dates/dateFormat';
|
||||
import { CUSTOM_PEER_PREMIUM } from '../../../../util/objects/customPeer';
|
||||
|
||||
import useSelector from '../../../hooks/data/useSelector';
|
||||
import useLastCallback from '../../../hooks/useLastCallback';
|
||||
import useOldLang from '../../../hooks/useOldLang';
|
||||
import useSelector from '../../../../hooks/data/useSelector';
|
||||
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||
import useOldLang from '../../../../hooks/useOldLang';
|
||||
|
||||
import Avatar from '../../common/Avatar';
|
||||
import StarIcon from '../../common/icons/StarIcon';
|
||||
import Avatar from '../../../common/Avatar';
|
||||
import StarIcon from '../../../common/icons/StarIcon';
|
||||
import PaidMediaThumb from './PaidMediaThumb';
|
||||
|
||||
import styles from './StarsTransactionItem.module.scss';
|
||||
@ -36,7 +36,7 @@ function selectOptionalPeer(peerId?: string) {
|
||||
}
|
||||
|
||||
const StarsTransactionItem = ({ transaction }: OwnProps) => {
|
||||
const { getStarsReceipt } = getActions();
|
||||
const { openStarsTransactionModal } = getActions();
|
||||
const {
|
||||
date,
|
||||
stars,
|
||||
@ -90,7 +90,7 @@ const StarsTransactionItem = ({ transaction }: OwnProps) => {
|
||||
}, [lang, peer, transaction]);
|
||||
|
||||
const handleClick = useLastCallback(() => {
|
||||
getStarsReceipt({ transaction });
|
||||
openStarsTransactionModal({ transaction });
|
||||
});
|
||||
|
||||
return (
|
||||
@ -0,0 +1,18 @@
|
||||
import type { FC } from '../../../../lib/teact/teact';
|
||||
import React from '../../../../lib/teact/teact';
|
||||
|
||||
import type { OwnProps } from './StarsTransactionModal';
|
||||
|
||||
import { Bundles } from '../../../../util/moduleLoader';
|
||||
|
||||
import useModuleLoader from '../../../../hooks/useModuleLoader';
|
||||
|
||||
const StarsTransactionModalAsync: FC<OwnProps> = (props) => {
|
||||
const { modal } = props;
|
||||
const StarsTransactionModal = useModuleLoader(Bundles.Extra, 'StarsTransactionInfoModal', !modal);
|
||||
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
return StarsTransactionModal ? <StarsTransactionModal {...props} /> : undefined;
|
||||
};
|
||||
|
||||
export default StarsTransactionModalAsync;
|
||||
@ -0,0 +1,69 @@
|
||||
.modal {
|
||||
z-index: calc(var(--z-media-viewer) - 1);
|
||||
}
|
||||
|
||||
.positive {
|
||||
color: var(--color-success);
|
||||
}
|
||||
|
||||
.negative {
|
||||
color: var(--color-error);
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.amount {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.325;
|
||||
}
|
||||
|
||||
.title, .description, .amount {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.tid {
|
||||
font-family: var(--font-family-monospace);
|
||||
font-size: 0.875rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.description {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: center;
|
||||
margin-block: 0.5rem;
|
||||
}
|
||||
|
||||
.starsBackground {
|
||||
position: absolute;
|
||||
height: 8rem;
|
||||
top: -8.5rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.mediaShift {
|
||||
top: -1.5rem;
|
||||
}
|
||||
|
||||
.copyIcon {
|
||||
margin-inline-start: 0.25rem;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.mediaPreview {
|
||||
margin-bottom: 2rem;
|
||||
cursor: var(--custom-cursor, pointer);
|
||||
}
|
||||
@ -0,0 +1,213 @@
|
||||
import type { FC } from '../../../../lib/teact/teact';
|
||||
import React, { memo, useMemo } from '../../../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../../../global';
|
||||
|
||||
import type {
|
||||
ApiPeer,
|
||||
ApiStarsTransactionPeer,
|
||||
} from '../../../../api/types';
|
||||
import type { TabState } from '../../../../global/types';
|
||||
import { MediaViewerOrigin } from '../../../../types';
|
||||
|
||||
import { getMessageLink } from '../../../../global/helpers';
|
||||
import { buildStarsTransactionCustomPeer, formatStarsTransactionAmount } from '../../../../global/helpers/payments';
|
||||
import { selectPeer } from '../../../../global/selectors';
|
||||
import buildClassName from '../../../../util/buildClassName';
|
||||
import { copyTextToClipboard } from '../../../../util/clipboard';
|
||||
import { formatDateTimeToString } from '../../../../util/dates/dateFormat';
|
||||
|
||||
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||
import useOldLang from '../../../../hooks/useOldLang';
|
||||
import usePrevious from '../../../../hooks/usePrevious';
|
||||
|
||||
import Icon from '../../../common/icons/Icon';
|
||||
import StarIcon from '../../../common/icons/StarIcon';
|
||||
import SafeLink from '../../../common/SafeLink';
|
||||
import TableInfoModal, { type TableData } from '../../common/TableInfoModal';
|
||||
import PaidMediaThumb from './PaidMediaThumb';
|
||||
|
||||
import styles from './StarsTransactionModal.module.scss';
|
||||
|
||||
import StarsBackground from '../../../../assets/stars-bg.png';
|
||||
|
||||
export type OwnProps = {
|
||||
modal: TabState['starsTransactionModal'];
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
peer?: ApiPeer;
|
||||
};
|
||||
|
||||
const StarsTransactionModal: FC<OwnProps & StateProps> = ({
|
||||
modal, peer,
|
||||
}) => {
|
||||
const { showNotification, openMediaViewer, closeStarsTransactionModal } = getActions();
|
||||
const lang = useOldLang();
|
||||
const { transaction } = modal || {};
|
||||
|
||||
const handleOpenMedia = useLastCallback(() => {
|
||||
const media = transaction?.extendedMedia;
|
||||
if (!media) return;
|
||||
|
||||
openMediaViewer({
|
||||
origin: MediaViewerOrigin.StarsTransaction,
|
||||
standaloneMedia: media.flatMap((item) => Object.values(item)),
|
||||
});
|
||||
});
|
||||
|
||||
const starModalData = useMemo(() => {
|
||||
if (!transaction) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const customPeer = (transaction.peer && transaction.peer.type !== 'peer'
|
||||
&& buildStarsTransactionCustomPeer(transaction.peer)) || undefined;
|
||||
|
||||
const peerId = transaction.peer?.type === 'peer' ? transaction.peer.id : undefined;
|
||||
const toName = transaction.peer && lang(getStarsPeerTitleKey(transaction.peer));
|
||||
|
||||
const title = transaction.title || (customPeer ? lang(customPeer.titleKey) : undefined);
|
||||
|
||||
const messageLink = peer && transaction.messageId
|
||||
? getMessageLink(peer, undefined, transaction.messageId) : undefined;
|
||||
|
||||
const media = transaction.extendedMedia;
|
||||
|
||||
const mediaAmount = media?.length || 0;
|
||||
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 description = transaction.description || (media ? mediaText : undefined);
|
||||
|
||||
const header = (
|
||||
<div className={styles.header}>
|
||||
{media && (
|
||||
<PaidMediaThumb
|
||||
className={buildClassName(styles.mediaPreview, 'transaction-media-preview')}
|
||||
media={media}
|
||||
onClick={handleOpenMedia}
|
||||
/>
|
||||
)}
|
||||
<img
|
||||
className={buildClassName(styles.starsBackground, media && styles.mediaShift)}
|
||||
src={StarsBackground}
|
||||
alt=""
|
||||
draggable={false}
|
||||
/>
|
||||
{title && <h1 className={styles.title}>{title}</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" />
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
const tableData: TableData = [];
|
||||
|
||||
tableData.push([
|
||||
lang(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} />]);
|
||||
}
|
||||
|
||||
if (transaction.id) {
|
||||
tableData.push([
|
||||
lang('Stars.Transaction.Id'),
|
||||
(
|
||||
<span
|
||||
className={styles.tid}
|
||||
onClick={() => {
|
||||
copyTextToClipboard(transaction.id!);
|
||||
showNotification({
|
||||
message: lang('StarsTransactionIDCopied'),
|
||||
});
|
||||
}}
|
||||
>
|
||||
{transaction.id}
|
||||
<Icon className={styles.copyIcon} name="copy" />
|
||||
</span>
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
tableData.push([
|
||||
lang('Stars.Transaction.Date'),
|
||||
formatDateTimeToString(transaction.date * 1000, lang.code, true),
|
||||
]);
|
||||
|
||||
const footerText = lang('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')} />
|
||||
{footerTextParts[1]}
|
||||
</span>
|
||||
);
|
||||
|
||||
return {
|
||||
header,
|
||||
tableData,
|
||||
footer,
|
||||
avatarPeer: !transaction.photo ? (peer || customPeer) : undefined,
|
||||
};
|
||||
}, [lang, transaction, peer]);
|
||||
|
||||
const prevModalData = usePrevious(starModalData);
|
||||
const renderingModalData = prevModalData || starModalData;
|
||||
|
||||
return (
|
||||
<TableInfoModal
|
||||
isOpen={Boolean(transaction)}
|
||||
className={styles.modal}
|
||||
header={renderingModalData?.header}
|
||||
tableData={renderingModalData?.tableData}
|
||||
footer={renderingModalData?.footer}
|
||||
noHeaderImage={Boolean(transaction?.extendedMedia)}
|
||||
headerAvatarWebPhoto={transaction?.photo}
|
||||
headerAvatarPeer={renderingModalData?.avatarPeer}
|
||||
buttonText={lang('OK')}
|
||||
onClose={closeStarsTransactionModal}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
return {
|
||||
peer,
|
||||
};
|
||||
},
|
||||
)(StarsTransactionModal));
|
||||
|
||||
function getStarsPeerTitleKey(peer: ApiStarsTransactionPeer) {
|
||||
switch (peer.type) {
|
||||
case 'appStore':
|
||||
return 'AppStore';
|
||||
case 'playMarket':
|
||||
return 'PlayMarket';
|
||||
case 'fragment':
|
||||
return 'Fragment';
|
||||
case 'premiumBot':
|
||||
return 'StarsTransactionBot';
|
||||
case 'ads':
|
||||
return 'StarsTransactionAds';
|
||||
default:
|
||||
return 'Stars.Transaction.Unsupported.Title';
|
||||
}
|
||||
}
|
||||
@ -1,211 +1,60 @@
|
||||
import type { FC } from '../../lib/teact/teact';
|
||||
import React, { memo, useEffect, useMemo } from '../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../global';
|
||||
import { withGlobal } from '../../global';
|
||||
|
||||
import type {
|
||||
ApiInvoice,
|
||||
ApiPeer,
|
||||
ApiReceipt, ApiReceiptRegular, ApiShippingAddress,
|
||||
ApiStarsTransactionPeer,
|
||||
} from '../../api/types';
|
||||
import { MediaViewerOrigin } from '../../types';
|
||||
import type { ApiInvoice, ApiShippingAddress, ApiWebDocument } from '../../api/types';
|
||||
import type { Price } from '../../types';
|
||||
|
||||
import { getMessageLink } from '../../global/helpers';
|
||||
import { buildStarsTransactionCustomPeer, formatStarsTransactionAmount } from '../../global/helpers/payments';
|
||||
import { selectPeer, selectTabState } from '../../global/selectors';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
import { copyTextToClipboard } from '../../util/clipboard';
|
||||
import { formatDateTimeToString } from '../../util/dates/dateFormat';
|
||||
import { selectTabState } from '../../global/selectors';
|
||||
|
||||
import useFlag from '../../hooks/useFlag';
|
||||
import useLastCallback from '../../hooks/useLastCallback';
|
||||
import useOldLang from '../../hooks/useOldLang';
|
||||
import useLang from '../../hooks/useLang';
|
||||
|
||||
import Icon from '../common/icons/Icon';
|
||||
import StarIcon from '../common/icons/StarIcon';
|
||||
import SafeLink from '../common/SafeLink';
|
||||
import TableInfoModal, { type TableData } from '../modals/common/TableInfoModal';
|
||||
import PaidMediaThumb from '../modals/stars/PaidMediaThumb';
|
||||
import Button from '../ui/Button';
|
||||
import Modal from '../ui/Modal';
|
||||
import Checkout from './Checkout';
|
||||
|
||||
import './PaymentModal.scss';
|
||||
import styles from './ReceiptModal.module.scss';
|
||||
|
||||
import StarsBackground from '../../assets/stars-bg.png';
|
||||
|
||||
export type OwnProps = {
|
||||
isOpen?: boolean;
|
||||
onClose: NoneToVoidFunction;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
receipt?: ApiReceipt;
|
||||
peer?: ApiPeer;
|
||||
prices?: Price[];
|
||||
shippingPrices: any;
|
||||
tipAmount?: number;
|
||||
totalAmount?: number;
|
||||
currency?: string;
|
||||
info?: {
|
||||
shippingAddress?: ApiShippingAddress;
|
||||
phone?: string;
|
||||
name?: string;
|
||||
};
|
||||
photo?: ApiWebDocument;
|
||||
text?: string;
|
||||
title?: string;
|
||||
credentialsTitle?: string;
|
||||
shippingMethod?: string;
|
||||
};
|
||||
|
||||
const ReceiptModal: FC<OwnProps & StateProps> = ({
|
||||
isOpen, receipt, peer, onClose,
|
||||
isOpen,
|
||||
onClose,
|
||||
prices,
|
||||
shippingPrices,
|
||||
tipAmount,
|
||||
totalAmount,
|
||||
currency,
|
||||
info,
|
||||
photo,
|
||||
text,
|
||||
title,
|
||||
credentialsTitle,
|
||||
shippingMethod,
|
||||
}) => {
|
||||
const { showNotification, openMediaViewer } = getActions();
|
||||
const lang = useOldLang();
|
||||
|
||||
const handleOpenMedia = useLastCallback(() => {
|
||||
const media = receipt?.type === 'stars' && receipt.media;
|
||||
if (!media) return;
|
||||
|
||||
openMediaViewer({
|
||||
origin: MediaViewerOrigin.StarsTransaction,
|
||||
standaloneMedia: media.flatMap((item) => Object.values(item)),
|
||||
});
|
||||
});
|
||||
|
||||
const starModalData = useMemo(() => {
|
||||
if (receipt?.type !== 'stars') return undefined;
|
||||
|
||||
const customPeer = (receipt.peer && receipt.peer.type !== 'peer' && buildStarsTransactionCustomPeer(receipt.peer))
|
||||
|| undefined;
|
||||
|
||||
const botId = receipt.botId || (receipt.peer?.type === 'peer' ? receipt.peer.id : undefined);
|
||||
const toName = receipt.peer && lang(getStarsPeerTitleKey(receipt.peer));
|
||||
|
||||
const title = receipt.title || (customPeer ? lang(customPeer.titleKey) : undefined);
|
||||
|
||||
const messageLink = peer && receipt.messageId ? getMessageLink(peer, undefined, receipt.messageId) : undefined;
|
||||
|
||||
const media = receipt.media;
|
||||
|
||||
const mediaAmount = media?.length || 0;
|
||||
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 description = receipt.text || (media ? mediaText : undefined);
|
||||
|
||||
const header = (
|
||||
<div className={styles.header}>
|
||||
{media && (
|
||||
<PaidMediaThumb
|
||||
className={buildClassName(styles.mediaPreview, 'transaction-media-preview')}
|
||||
media={media}
|
||||
onClick={handleOpenMedia}
|
||||
/>
|
||||
)}
|
||||
<img
|
||||
className={buildClassName(styles.starsBackground, receipt.media && styles.mediaShift)}
|
||||
src={StarsBackground}
|
||||
alt=""
|
||||
draggable={false}
|
||||
/>
|
||||
{title && <h1 className={styles.title}>{title}</h1>}
|
||||
<p className={styles.description}>{description}</p>
|
||||
<p className={styles.amount}>
|
||||
<span className={buildClassName(styles.amount, receipt.totalAmount < 0 ? styles.negative : styles.positive)}>
|
||||
{formatStarsTransactionAmount(receipt.totalAmount)}
|
||||
</span>
|
||||
<StarIcon type="gold" size="big" />
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
const tableData: TableData = [];
|
||||
|
||||
tableData.push([
|
||||
lang(receipt.totalAmount < 0 ? 'Stars.Transaction.To' : 'Stars.Transaction.Via'),
|
||||
botId ? { chatId: botId } : toName || '',
|
||||
]);
|
||||
|
||||
if (messageLink) {
|
||||
tableData.push([lang('Stars.Transaction.Media'), <SafeLink url={messageLink} text={messageLink} />]);
|
||||
}
|
||||
|
||||
tableData.push([
|
||||
lang('Stars.Transaction.Id'),
|
||||
(
|
||||
<span
|
||||
className={styles.tid}
|
||||
onClick={() => {
|
||||
copyTextToClipboard(receipt.transactionId);
|
||||
showNotification({
|
||||
message: lang('StarsTransactionIDCopied'),
|
||||
});
|
||||
}}
|
||||
>
|
||||
{receipt.transactionId}
|
||||
<Icon className={styles.copyIcon} name="copy" />
|
||||
</span>
|
||||
),
|
||||
]);
|
||||
|
||||
tableData.push([
|
||||
lang('Stars.Transaction.Date'),
|
||||
formatDateTimeToString(receipt.date * 1000, lang.code, true),
|
||||
]);
|
||||
|
||||
const footerText = lang('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')} />
|
||||
{footerTextParts[1]}
|
||||
</span>
|
||||
);
|
||||
|
||||
return {
|
||||
header,
|
||||
tableData,
|
||||
footer,
|
||||
avatarPeer: !receipt.photo ? (peer || customPeer) : undefined,
|
||||
};
|
||||
}, [lang, receipt, peer]);
|
||||
|
||||
if (receipt?.type === 'regular') {
|
||||
return <ReceiptModalRegular isOpen={isOpen} receipt={receipt} onClose={onClose} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<TableInfoModal
|
||||
isOpen={isOpen}
|
||||
className={styles.modal}
|
||||
header={starModalData?.header}
|
||||
tableData={starModalData?.tableData}
|
||||
footer={starModalData?.footer}
|
||||
noHeaderImage={Boolean(receipt?.media)}
|
||||
headerAvatarWebPhoto={receipt?.photo}
|
||||
headerAvatarPeer={starModalData?.avatarPeer}
|
||||
buttonText={lang('OK')}
|
||||
onClose={onClose}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
function ReceiptModalRegular({
|
||||
isOpen, receipt, onClose,
|
||||
}: {
|
||||
isOpen?: boolean;
|
||||
receipt: ApiReceiptRegular;
|
||||
onClose: NoneToVoidFunction;
|
||||
}) {
|
||||
const {
|
||||
credentialsTitle,
|
||||
currency,
|
||||
prices,
|
||||
tipAmount,
|
||||
totalAmount,
|
||||
info,
|
||||
photo,
|
||||
shippingMethod,
|
||||
shippingPrices,
|
||||
text,
|
||||
title,
|
||||
} = receipt;
|
||||
const lang = useOldLang();
|
||||
const lang = useLang();
|
||||
|
||||
const [isModalOpen, openModal, closeModal] = useFlag();
|
||||
|
||||
@ -265,18 +114,37 @@ function ReceiptModalRegular({
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default memo(withGlobal<OwnProps>(
|
||||
(global): StateProps => {
|
||||
const { receipt } = selectTabState(global).payment;
|
||||
|
||||
const peerId = receipt?.type === 'stars' && (receipt.botId || (receipt.peer?.type === 'peer' && receipt.peer.id));
|
||||
const peer = peerId ? selectPeer(global, peerId) : undefined;
|
||||
const {
|
||||
currency,
|
||||
prices,
|
||||
info,
|
||||
totalAmount,
|
||||
credentialsTitle,
|
||||
shippingPrices,
|
||||
shippingMethod,
|
||||
photo,
|
||||
text,
|
||||
title,
|
||||
tipAmount,
|
||||
} = (receipt || {});
|
||||
|
||||
return {
|
||||
receipt,
|
||||
peer,
|
||||
currency,
|
||||
prices,
|
||||
info,
|
||||
tipAmount,
|
||||
totalAmount,
|
||||
credentialsTitle,
|
||||
shippingPrices,
|
||||
shippingMethod,
|
||||
photo,
|
||||
text,
|
||||
title,
|
||||
};
|
||||
},
|
||||
)(ReceiptModal));
|
||||
@ -304,20 +172,3 @@ function getCheckoutInfo(paymentMethod?: string,
|
||||
shippingMethod,
|
||||
};
|
||||
}
|
||||
|
||||
function getStarsPeerTitleKey(peer: ApiStarsTransactionPeer) {
|
||||
switch (peer.type) {
|
||||
case 'appStore':
|
||||
return 'AppStore';
|
||||
case 'playMarket':
|
||||
return 'PlayMarket';
|
||||
case 'fragment':
|
||||
return 'Fragment';
|
||||
case 'premiumBot':
|
||||
return 'StarsTransactionBot';
|
||||
case 'ads':
|
||||
return 'StarsTransactionAds';
|
||||
default:
|
||||
return 'Stars.Transaction.Unsupported.Title';
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,11 +12,13 @@ import { buildQueryString } from '../../../util/requestQuery';
|
||||
import { extractCurrentThemeParams } from '../../../util/themeStyle';
|
||||
import { callApi } from '../../../api/gramjs';
|
||||
import { isChatChannel, isChatSuperGroup } from '../../helpers';
|
||||
import { getRequestInputInvoice } from '../../helpers/payments';
|
||||
import { getRequestInputInvoice, getStarsTransactionFromGift } from '../../helpers/payments';
|
||||
import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
||||
import {
|
||||
addChats,
|
||||
addUsers, appendStarsTransactions, closeInvoice,
|
||||
openStarsTransactionFromReceipt,
|
||||
openStarsTransactionModal,
|
||||
setInvoiceInfo, setPaymentForm,
|
||||
setPaymentStep,
|
||||
setReceipt,
|
||||
@ -24,7 +26,6 @@ import {
|
||||
setSmartGlocalCardInfo, setStripeCardInfo,
|
||||
updateChatFullInfo,
|
||||
updatePayment,
|
||||
updateReceiptFromStarsTransaction,
|
||||
updateShippingOptions,
|
||||
updateStarsBalance,
|
||||
} from '../../reducers';
|
||||
@ -32,6 +33,7 @@ import { updateTabState } from '../../reducers/tabs';
|
||||
import {
|
||||
selectChat,
|
||||
selectChatFullInfo,
|
||||
selectChatMessage,
|
||||
selectPaymentFormId,
|
||||
selectPaymentInputInvoice, selectPaymentRequestId,
|
||||
selectProviderPublicToken,
|
||||
@ -132,15 +134,14 @@ addActionHandler('getReceipt', async (global, actions, payload): Promise<void> =
|
||||
|
||||
global = getGlobal();
|
||||
global = addUsers(global, buildCollectionByKey(result.users, 'id'));
|
||||
global = setReceipt(global, result.receipt, tabId);
|
||||
if (result.receipt.type === 'stars') {
|
||||
global = openStarsTransactionFromReceipt(global, result.receipt, tabId);
|
||||
} else {
|
||||
global = setReceipt(global, result.receipt, tabId);
|
||||
}
|
||||
setGlobal(global);
|
||||
});
|
||||
|
||||
addActionHandler('getStarsReceipt', (global, actions, payload): ActionReturnType => {
|
||||
const { transaction, tabId = getCurrentTabId() } = payload;
|
||||
return updateReceiptFromStarsTransaction(global, transaction, tabId);
|
||||
});
|
||||
|
||||
addActionHandler('clearPaymentError', (global, actions, payload): ActionReturnType => {
|
||||
const { tabId = getCurrentTabId() } = payload || {};
|
||||
global = updateTabState(global, {
|
||||
@ -534,37 +535,20 @@ addActionHandler('closeStarsGiftingModal', (global, actions, payload): ActionRet
|
||||
}, tabId);
|
||||
});
|
||||
|
||||
addActionHandler('openStarGiftInfoModal', (global, actions, payload): ActionReturnType => {
|
||||
addActionHandler('openStarsTransactionFromGift', (global, actions, payload): ActionReturnType => {
|
||||
const {
|
||||
toUserId,
|
||||
stars,
|
||||
date,
|
||||
chatId,
|
||||
messageId,
|
||||
tabId = getCurrentTabId(),
|
||||
} = payload || {};
|
||||
|
||||
if (!stars || !toUserId || !date) {
|
||||
return;
|
||||
}
|
||||
const message = selectChatMessage(global, chatId, messageId);
|
||||
if (!message) return undefined;
|
||||
|
||||
global = getGlobal();
|
||||
const transaction = getStarsTransactionFromGift(message);
|
||||
if (!transaction) return undefined;
|
||||
|
||||
global = updateTabState(global, {
|
||||
starGiftInfoModal: {
|
||||
toUserId,
|
||||
stars,
|
||||
date,
|
||||
isOpen: true,
|
||||
},
|
||||
}, tabId);
|
||||
setGlobal(global);
|
||||
});
|
||||
|
||||
addActionHandler('closeStarGiftInfoModal', (global, actions, payload): ActionReturnType => {
|
||||
const { tabId = getCurrentTabId() } = payload || {};
|
||||
|
||||
return updateTabState(global, {
|
||||
starGiftInfoModal: undefined,
|
||||
}, tabId);
|
||||
return openStarsTransactionModal(global, transaction, tabId);
|
||||
});
|
||||
|
||||
addActionHandler('openPremiumGiftModal', async (global, actions, payload): Promise<void> => {
|
||||
|
||||
@ -2,7 +2,9 @@ import type { ActionReturnType } from '../../types';
|
||||
|
||||
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
||||
import { addActionHandler } from '../../index';
|
||||
import { clearPayment, closeInvoice, updatePayment } from '../../reducers';
|
||||
import {
|
||||
clearPayment, closeInvoice, openStarsTransactionModal, updatePayment,
|
||||
} from '../../reducers';
|
||||
import { updateTabState } from '../../reducers/tabs';
|
||||
import { selectTabState } from '../../selectors';
|
||||
|
||||
@ -72,3 +74,16 @@ addActionHandler('closeStarsBalanceModal', (global, actions, payload): ActionRet
|
||||
starsBalanceModal: undefined,
|
||||
}, tabId);
|
||||
});
|
||||
|
||||
addActionHandler('openStarsTransactionModal', (global, actions, payload): ActionReturnType => {
|
||||
const { transaction, tabId = getCurrentTabId() } = payload;
|
||||
return openStarsTransactionModal(global, transaction, tabId);
|
||||
});
|
||||
|
||||
addActionHandler('closeStarsTransactionModal', (global, actions, payload): ActionReturnType => {
|
||||
const { tabId = getCurrentTabId() } = payload || {};
|
||||
|
||||
return updateTabState(global, {
|
||||
starsTransactionModal: undefined,
|
||||
}, tabId);
|
||||
});
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
import type {
|
||||
ApiInputInvoice, ApiRequestInputInvoice, ApiStarsTransactionPeer, ApiStarsTransactionPeerPeer,
|
||||
ApiInputInvoice,
|
||||
ApiMessage,
|
||||
ApiRequestInputInvoice,
|
||||
ApiStarsTransaction,
|
||||
ApiStarsTransactionPeer,
|
||||
ApiStarsTransactionPeerPeer,
|
||||
} from '../../api/types';
|
||||
import type { CustomPeer } from '../../types';
|
||||
import type { GlobalState } from '../types';
|
||||
@ -141,7 +146,7 @@ export function buildStarsTransactionCustomPeer(
|
||||
isCustomPeer: true,
|
||||
titleKey: 'Stars.Intro.Transaction.FragmentTopUp.Title',
|
||||
subtitleKey: 'Stars.Intro.Transaction.FragmentTopUp.Subtitle',
|
||||
peerColorId: -1, // Defaults to black
|
||||
customPeerAvatarColor: '#000000',
|
||||
};
|
||||
}
|
||||
|
||||
@ -182,3 +187,23 @@ export function formatStarsTransactionAmount(amount: number) {
|
||||
|
||||
return `+ ${formatInteger(amount)}`;
|
||||
}
|
||||
|
||||
export function getStarsTransactionFromGift(message: ApiMessage): ApiStarsTransaction | undefined {
|
||||
const { action } = message.content;
|
||||
|
||||
if (action?.type !== 'giftStars') return undefined;
|
||||
|
||||
const { transactionId, stars } = action;
|
||||
|
||||
return {
|
||||
id: transactionId!,
|
||||
stars: stars!,
|
||||
peer: {
|
||||
type: 'peer',
|
||||
id: message.isOutgoing ? message.chatId : message.senderId!,
|
||||
},
|
||||
date: message.date,
|
||||
isGift: true,
|
||||
isMyGift: message.isOutgoing || undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import type {
|
||||
ApiInvoice, ApiPaymentForm, ApiReceipt,
|
||||
ApiInvoice, ApiPaymentForm,
|
||||
ApiReceiptRegular,
|
||||
ApiReceiptStars,
|
||||
ApiStarsTransaction,
|
||||
} from '../../api/types';
|
||||
@ -8,7 +9,6 @@ import type {
|
||||
GlobalState, StarsTransactionType, TabArgs, TabState,
|
||||
} from '../types';
|
||||
|
||||
import { STARS_CURRENCY_CODE } from '../../config';
|
||||
import { getCurrentTabId } from '../../util/establishMultitabRole';
|
||||
import { selectTabState } from '../selectors';
|
||||
import { updateTabState } from './tabs';
|
||||
@ -113,7 +113,7 @@ export function setConfirmPaymentUrl<T extends GlobalState>(
|
||||
|
||||
export function setReceipt<T extends GlobalState>(
|
||||
global: T,
|
||||
receipt?: ApiReceipt,
|
||||
receipt?: ApiReceiptRegular,
|
||||
...[tabId = getCurrentTabId()]: TabArgs<T>
|
||||
): T {
|
||||
if (!receipt) {
|
||||
@ -187,22 +187,30 @@ export function appendStarsTransactions<T extends GlobalState>(
|
||||
};
|
||||
}
|
||||
|
||||
export function updateReceiptFromStarsTransaction<T extends GlobalState>(
|
||||
export function openStarsTransactionModal<T extends GlobalState>(
|
||||
global: T, transaction: ApiStarsTransaction, ...[tabId = getCurrentTabId()]: TabArgs<T>
|
||||
): T {
|
||||
const receipt: ApiReceiptStars = {
|
||||
type: 'stars',
|
||||
totalAmount: transaction.stars,
|
||||
currency: STARS_CURRENCY_CODE,
|
||||
peer: transaction.peer,
|
||||
date: transaction.date,
|
||||
text: transaction.description,
|
||||
title: transaction.title,
|
||||
transactionId: transaction.id,
|
||||
photo: transaction.photo,
|
||||
media: transaction.extendedMedia,
|
||||
messageId: transaction.messageId,
|
||||
return updateTabState(global, {
|
||||
starsTransactionModal: {
|
||||
transaction,
|
||||
},
|
||||
}, tabId);
|
||||
}
|
||||
|
||||
export function openStarsTransactionFromReceipt<T extends GlobalState>(
|
||||
global: T, receipt: ApiReceiptStars, ...[tabId = getCurrentTabId()]: TabArgs<T>
|
||||
): T {
|
||||
const transaction: ApiStarsTransaction = {
|
||||
id: receipt.transactionId,
|
||||
peer: receipt.peer,
|
||||
stars: receipt.totalAmount,
|
||||
date: receipt.date,
|
||||
title: receipt.title,
|
||||
description: receipt.text,
|
||||
photo: receipt.photo,
|
||||
extendedMedia: receipt.media,
|
||||
messageId: receipt.messageId,
|
||||
};
|
||||
|
||||
return updatePayment(global, { receipt }, tabId);
|
||||
return openStarsTransactionModal(global, transaction, tabId);
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ import type {
|
||||
ApiQuickReply,
|
||||
ApiReaction,
|
||||
ApiReactionKey,
|
||||
ApiReceipt,
|
||||
ApiReceiptRegular,
|
||||
ApiReportReason,
|
||||
ApiSavedReactionTag,
|
||||
ApiSendMessageAction,
|
||||
@ -547,7 +547,7 @@ export type TabState = {
|
||||
};
|
||||
passwordMissing?: boolean;
|
||||
savedCredentials?: ApiPaymentCredentials[];
|
||||
receipt?: ApiReceipt;
|
||||
receipt?: ApiReceiptRegular;
|
||||
error?: {
|
||||
field?: string;
|
||||
message?: string;
|
||||
@ -720,13 +720,6 @@ export type TabState = {
|
||||
isOpen?: boolean;
|
||||
};
|
||||
|
||||
starGiftInfoModal?: {
|
||||
isOpen?: boolean;
|
||||
toUserId: string;
|
||||
date: number;
|
||||
stars: number;
|
||||
};
|
||||
|
||||
starsGiftModal?: {
|
||||
isCompleted?: boolean;
|
||||
isOpen?: boolean;
|
||||
@ -734,6 +727,10 @@ export type TabState = {
|
||||
starsGiftOptions?: ApiStarsGiftOption[];
|
||||
};
|
||||
|
||||
starsTransactionModal?: {
|
||||
transaction: ApiStarsTransaction;
|
||||
};
|
||||
|
||||
giftModal?: {
|
||||
isCompleted?: boolean;
|
||||
isOpen?: boolean;
|
||||
@ -1770,9 +1767,14 @@ export interface ActionPayloads {
|
||||
chatId: string;
|
||||
messageId: number;
|
||||
} & WithTabId;
|
||||
getStarsReceipt: {
|
||||
openStarsTransactionModal: {
|
||||
transaction: ApiStarsTransaction;
|
||||
} & WithTabId;
|
||||
openStarsTransactionFromGift: {
|
||||
chatId: string;
|
||||
messageId: number;
|
||||
} & WithTabId;
|
||||
closeStarsTransactionModal: WithTabId | undefined;
|
||||
sendCredentialsInfo: {
|
||||
credentials: ApiCredentials;
|
||||
} & WithTabId;
|
||||
@ -3241,13 +3243,6 @@ export interface ActionPayloads {
|
||||
} & WithTabId) | undefined;
|
||||
closeStarsGiftModal: WithTabId | undefined;
|
||||
|
||||
openStarGiftInfoModal: ({
|
||||
toUserId?: string;
|
||||
stars?: number;
|
||||
date?: number;
|
||||
} & WithTabId) | undefined;
|
||||
closeStarGiftInfoModal: WithTabId | undefined;
|
||||
|
||||
setEmojiStatus: {
|
||||
emojiStatus: ApiSticker;
|
||||
expires?: number;
|
||||
|
||||
@ -1633,6 +1633,7 @@ payments.getStarsStatus#104fcfa7 peer:InputPeer = payments.StarsStatus;
|
||||
payments.getStarsTransactions#97938d5a flags:# inbound:flags.0?true outbound:flags.1?true ascending:flags.2?true peer:InputPeer offset:string limit:int = payments.StarsStatus;
|
||||
payments.sendStarsForm#2bb731d flags:# form_id:long invoice:InputInvoice = payments.PaymentResult;
|
||||
payments.refundStarsCharge#25ae8f4a user_id:InputUser charge_id:string = Updates;
|
||||
payments.getStarsTransactionsByID#27842d2e peer:InputPeer id:Vector<InputStarsTransaction> = payments.StarsStatus;
|
||||
payments.getStarsGiftOptions#d3c96bc8 flags:# user_id:flags.0?InputUser = Vector<StarsGiftOption>;
|
||||
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;
|
||||
@ -1698,4 +1699,4 @@ premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:
|
||||
premium.getMyBoosts#be77b4a = premium.MyBoosts;
|
||||
premium.applyBoost#6b7da746 flags:# slots:flags.0?Vector<int> peer:InputPeer = premium.MyBoosts;
|
||||
premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus;
|
||||
fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo;`;
|
||||
fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo;`;
|
||||
@ -361,6 +361,7 @@
|
||||
"payments.getStarsTopupOptions",
|
||||
"payments.getStarsStatus",
|
||||
"payments.getStarsTransactions",
|
||||
"payments.getStarsTransactionsByID",
|
||||
"payments.sendStarsForm",
|
||||
"payments.getStarsGiftOptions",
|
||||
"payments.refundStarsCharge",
|
||||
|
||||
@ -520,6 +520,7 @@ export interface CustomPeer {
|
||||
avatarIcon: IconName;
|
||||
isAvatarSquare?: boolean;
|
||||
peerColorId?: number;
|
||||
customPeerAvatarColor?: string;
|
||||
withPremiumGradient?: boolean;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user