Paid Messages: Follow up (#5790)
This commit is contained in:
parent
71b7c9e9bb
commit
3055df600b
@ -9,7 +9,7 @@ import type {
|
|||||||
} from '../../../lib/secret-sauce';
|
} from '../../../lib/secret-sauce';
|
||||||
import type { ApiGroupCall, ApiPhoneCall } from '../../types';
|
import type { ApiGroupCall, ApiPhoneCall } from '../../types';
|
||||||
|
|
||||||
import { getApiChatIdFromMtpPeer, isPeerUser } from './peers';
|
import { getApiChatIdFromMtpPeer, isMtpPeerUser } from './peers';
|
||||||
|
|
||||||
export function buildApiGroupCallParticipant(participant: GramJs.GroupCallParticipant): GroupCallParticipant {
|
export function buildApiGroupCallParticipant(participant: GramJs.GroupCallParticipant): GroupCallParticipant {
|
||||||
const {
|
const {
|
||||||
@ -33,7 +33,7 @@ export function buildApiGroupCallParticipant(participant: GramJs.GroupCallPartic
|
|||||||
raiseHandRating: raiseHandRating?.toString(),
|
raiseHandRating: raiseHandRating?.toString(),
|
||||||
volume,
|
volume,
|
||||||
date: new Date(date),
|
date: new Date(date),
|
||||||
isUser: isPeerUser(peer),
|
isUser: isMtpPeerUser(peer),
|
||||||
id: getApiChatIdFromMtpPeer(peer),
|
id: getApiChatIdFromMtpPeer(peer),
|
||||||
video: video ? buildApiGroupCallParticipantVideo(video) : undefined,
|
video: video ? buildApiGroupCallParticipantVideo(video) : undefined,
|
||||||
presentation: presentation ? buildApiGroupCallParticipantVideo(presentation) : undefined,
|
presentation: presentation ? buildApiGroupCallParticipantVideo(presentation) : undefined,
|
||||||
|
|||||||
@ -36,8 +36,8 @@ import {
|
|||||||
buildApiPeerColor,
|
buildApiPeerColor,
|
||||||
buildApiPeerId,
|
buildApiPeerId,
|
||||||
getApiChatIdFromMtpPeer,
|
getApiChatIdFromMtpPeer,
|
||||||
isPeerChat,
|
isMtpPeerChat,
|
||||||
isPeerUser,
|
isMtpPeerUser,
|
||||||
} from './peers';
|
} from './peers';
|
||||||
import { buildApiReaction } from './reactions';
|
import { buildApiReaction } from './reactions';
|
||||||
|
|
||||||
@ -295,9 +295,9 @@ export function getApiChatTypeFromPeerEntity(peerEntity: GramJs.TypeChat | GramJ
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getPeerKey(peer: GramJs.TypePeer) {
|
export function getPeerKey(peer: GramJs.TypePeer) {
|
||||||
if (isPeerUser(peer)) {
|
if (isMtpPeerUser(peer)) {
|
||||||
return `user${peer.userId}`;
|
return `user${peer.userId}`;
|
||||||
} else if (isPeerChat(peer)) {
|
} else if (isMtpPeerChat(peer)) {
|
||||||
return `chat${peer.chatId}`;
|
return `chat${peer.chatId}`;
|
||||||
} else {
|
} else {
|
||||||
return `chat${peer.channelId}`;
|
return `chat${peer.channelId}`;
|
||||||
@ -305,7 +305,7 @@ export function getPeerKey(peer: GramJs.TypePeer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getApiChatTitleFromMtpPeer(peer: GramJs.TypePeer, peerEntity: GramJs.User | GramJs.Chat) {
|
export function getApiChatTitleFromMtpPeer(peer: GramJs.TypePeer, peerEntity: GramJs.User | GramJs.Chat) {
|
||||||
if (isPeerUser(peer)) {
|
if (isMtpPeerUser(peer)) {
|
||||||
return getUserName(peerEntity as GramJs.User);
|
return getUserName(peerEntity as GramJs.User);
|
||||||
} else {
|
} else {
|
||||||
return (peerEntity as GramJs.Chat).title;
|
return (peerEntity as GramJs.Chat).title;
|
||||||
|
|||||||
@ -6,15 +6,15 @@ import type { ApiEmojiStatusType, ApiPeerColor } from '../../types';
|
|||||||
import { CHANNEL_ID_LENGTH } from '../../../config';
|
import { CHANNEL_ID_LENGTH } from '../../../config';
|
||||||
import { numberToHexColor } from '../../../util/colors';
|
import { numberToHexColor } from '../../../util/colors';
|
||||||
|
|
||||||
export function isPeerUser(peer: GramJs.TypePeer | GramJs.TypeInputPeer): peer is GramJs.PeerUser {
|
export function isMtpPeerUser(peer: GramJs.TypePeer | GramJs.TypeInputPeer): peer is GramJs.PeerUser {
|
||||||
return peer.hasOwnProperty('userId');
|
return peer.hasOwnProperty('userId');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isPeerChat(peer: GramJs.TypePeer | GramJs.TypeInputPeer): peer is GramJs.PeerChat {
|
export function isMtpPeerChat(peer: GramJs.TypePeer | GramJs.TypeInputPeer): peer is GramJs.PeerChat {
|
||||||
return peer.hasOwnProperty('chatId');
|
return peer.hasOwnProperty('chatId');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isPeerChannel(peer: GramJs.TypePeer | GramJs.TypeInputPeer): peer is GramJs.PeerChannel {
|
export function isMtpPeerChannel(peer: GramJs.TypePeer | GramJs.TypeInputPeer): peer is GramJs.PeerChannel {
|
||||||
return peer.hasOwnProperty('channelId');
|
return peer.hasOwnProperty('channelId');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,9 +34,9 @@ export function buildApiPeerId(id: BigInt.BigInteger, type: 'user' | 'chat' | 'c
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getApiChatIdFromMtpPeer(peer: GramJs.TypePeer | GramJs.TypeInputPeer) {
|
export function getApiChatIdFromMtpPeer(peer: GramJs.TypePeer | GramJs.TypeInputPeer) {
|
||||||
if (isPeerUser(peer)) {
|
if (isMtpPeerUser(peer)) {
|
||||||
return buildApiPeerId(peer.userId, 'user');
|
return buildApiPeerId(peer.userId, 'user');
|
||||||
} else if (isPeerChat(peer)) {
|
} else if (isMtpPeerChat(peer)) {
|
||||||
return buildApiPeerId(peer.chatId, 'chat');
|
return buildApiPeerId(peer.chatId, 'chat');
|
||||||
} else {
|
} else {
|
||||||
return buildApiPeerId((peer as GramJs.InputPeerChannel).channelId, 'channel');
|
return buildApiPeerId((peer as GramJs.InputPeerChannel).channelId, 'channel');
|
||||||
|
|||||||
@ -258,6 +258,17 @@ export async function addNoPaidMessagesException({ user, shouldRefundCharged }:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function fetchPaidMessagesRevenue({ user }: {
|
||||||
|
user: ApiUser;
|
||||||
|
shouldRefundCharged?: boolean;
|
||||||
|
}) {
|
||||||
|
const result = await invokeRequest(new GramJs.account.GetPaidMessagesRevenue({
|
||||||
|
userId: buildInputEntity(user.id, user.accessHash) as GramJs.InputUser,
|
||||||
|
}));
|
||||||
|
if (!result) return undefined;
|
||||||
|
return result.starsAmount.toJSNumber();
|
||||||
|
}
|
||||||
|
|
||||||
export async function fetchProfilePhotos({
|
export async function fetchProfilePhotos({
|
||||||
peer,
|
peer,
|
||||||
offset = 0,
|
offset = 0,
|
||||||
|
|||||||
@ -1890,4 +1890,7 @@
|
|||||||
"PaidMessageTransaction_one" = "Fee for {count} Message";
|
"PaidMessageTransaction_one" = "Fee for {count} Message";
|
||||||
"PaidMessageTransaction_other" = "Fee for {count} Messages";
|
"PaidMessageTransaction_other" = "Fee for {count} Messages";
|
||||||
"PaidMessageTransactionDescription" = "You receive **{percent}** of the price that you charge for each incoming message.";
|
"PaidMessageTransactionDescription" = "You receive **{percent}** of the price that you charge for each incoming message.";
|
||||||
"PaidMessageTransactionTotal" = "Total";
|
"PaidMessageTransactionTotal" = "Total";
|
||||||
|
"DescriptionRestrictedMedia" = "Posting media content is not allowed in this group.";
|
||||||
|
"DescriptionScheduledPaidMediaNotAllowed" = "Posting scheduled paid media content is not allowed";
|
||||||
|
"DescriptionScheduledPaidMessagesNotAllowed" = "Scheduled paid messages is not allowed";
|
||||||
@ -12,3 +12,4 @@ export { default as GiftUpgradeModal } from '../components/modals/gift/upgrade/G
|
|||||||
export { default as GiftStatusInfoModal } from '../components/modals/gift/status/GiftStatusInfoModal';
|
export { default as GiftStatusInfoModal } from '../components/modals/gift/status/GiftStatusInfoModal';
|
||||||
export { default as GiftWithdrawModal } from '../components/modals/gift/withdraw/GiftWithdrawModal';
|
export { default as GiftWithdrawModal } from '../components/modals/gift/withdraw/GiftWithdrawModal';
|
||||||
export { default as GiftTransferModal } from '../components/modals/gift/transfer/GiftTransferModal';
|
export { default as GiftTransferModal } from '../components/modals/gift/transfer/GiftTransferModal';
|
||||||
|
export { default as ChatRefundModal } from '../components/modals/stars/chatRefund/ChatRefundModal';
|
||||||
|
|||||||
@ -21,10 +21,9 @@ import {
|
|||||||
isAnonymousForwardsChat,
|
isAnonymousForwardsChat,
|
||||||
isChatWithRepliesBot,
|
isChatWithRepliesBot,
|
||||||
isDeletedUser,
|
isDeletedUser,
|
||||||
isPeerChat,
|
|
||||||
isPeerUser,
|
|
||||||
isUserId,
|
isUserId,
|
||||||
} from '../../global/helpers';
|
} from '../../global/helpers';
|
||||||
|
import { isApiPeerChat, isApiPeerUser } from '../../global/helpers/peers';
|
||||||
import buildClassName, { createClassNameBuilder } from '../../util/buildClassName';
|
import buildClassName, { createClassNameBuilder } from '../../util/buildClassName';
|
||||||
import buildStyle from '../../util/buildStyle';
|
import buildStyle from '../../util/buildStyle';
|
||||||
import { getFirstLetters } from '../../util/textFormat';
|
import { getFirstLetters } from '../../util/textFormat';
|
||||||
@ -117,8 +116,8 @@ const Avatar: FC<OwnProps> = ({
|
|||||||
const videoLoopCountRef = useRef(0);
|
const videoLoopCountRef = useRef(0);
|
||||||
const isCustomPeer = peer && 'isCustomPeer' in peer;
|
const isCustomPeer = peer && 'isCustomPeer' in peer;
|
||||||
const realPeer = peer && !isCustomPeer ? peer : undefined;
|
const realPeer = peer && !isCustomPeer ? peer : undefined;
|
||||||
const user = realPeer && isPeerUser(realPeer) ? realPeer : undefined;
|
const user = realPeer && isApiPeerUser(realPeer) ? realPeer : undefined;
|
||||||
const chat = realPeer && isPeerChat(realPeer) ? realPeer : undefined;
|
const chat = realPeer && isApiPeerChat(realPeer) ? realPeer : undefined;
|
||||||
const isDeleted = user && isDeletedUser(user);
|
const isDeleted = user && isDeletedUser(user);
|
||||||
const isReplies = realPeer && isChatWithRepliesBot(realPeer.id);
|
const isReplies = realPeer && isChatWithRepliesBot(realPeer.id);
|
||||||
const isAnonymousForwards = realPeer && isAnonymousForwardsChat(realPeer.id);
|
const isAnonymousForwards = realPeer && isAnonymousForwardsChat(realPeer.id);
|
||||||
|
|||||||
@ -57,7 +57,6 @@ import { requestMeasure, requestNextMutation } from '../../lib/fasterdom/fasterd
|
|||||||
import {
|
import {
|
||||||
canEditMedia,
|
canEditMedia,
|
||||||
getAllowedAttachmentOptions,
|
getAllowedAttachmentOptions,
|
||||||
getPeerTitle,
|
|
||||||
getReactionKey,
|
getReactionKey,
|
||||||
getStoryKey,
|
getStoryKey,
|
||||||
isChatAdmin,
|
isChatAdmin,
|
||||||
@ -68,6 +67,7 @@ import {
|
|||||||
isUserId,
|
isUserId,
|
||||||
} from '../../global/helpers';
|
} from '../../global/helpers';
|
||||||
import { getChatNotifySettings } from '../../global/helpers/notifications';
|
import { getChatNotifySettings } from '../../global/helpers/notifications';
|
||||||
|
import { getPeerTitle } from '../../global/helpers/peers';
|
||||||
import {
|
import {
|
||||||
selectBot,
|
selectBot,
|
||||||
selectCanPlayAnimatedEmojis,
|
selectCanPlayAnimatedEmojis,
|
||||||
@ -288,6 +288,8 @@ type StateProps =
|
|||||||
shouldPaidMessageAutoApprove?: boolean;
|
shouldPaidMessageAutoApprove?: boolean;
|
||||||
isSilentPosting?: boolean;
|
isSilentPosting?: boolean;
|
||||||
isPaymentMessageConfirmDialogOpen: boolean;
|
isPaymentMessageConfirmDialogOpen: boolean;
|
||||||
|
starsBalance: number;
|
||||||
|
isStarsBalanceModalOpen: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MainButtonState {
|
enum MainButtonState {
|
||||||
@ -406,6 +408,8 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
onBlur,
|
onBlur,
|
||||||
onForward,
|
onForward,
|
||||||
isPaymentMessageConfirmDialogOpen,
|
isPaymentMessageConfirmDialogOpen,
|
||||||
|
starsBalance,
|
||||||
|
isStarsBalanceModalOpen,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
sendMessage,
|
sendMessage,
|
||||||
@ -520,8 +524,13 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
canSendStickers, canSendGifs, canAttachMedia, canAttachPolls, canAttachEmbedLinks,
|
canSendStickers, canSendGifs, canAttachMedia, canAttachPolls, canAttachEmbedLinks,
|
||||||
canSendVoices, canSendPlainText, canSendAudios, canSendVideos, canSendPhotos, canSendDocuments,
|
canSendVoices, canSendPlainText, canSendAudios, canSendVideos, canSendPhotos, canSendDocuments,
|
||||||
} = useMemo(
|
} = useMemo(
|
||||||
() => getAllowedAttachmentOptions(chat, chatFullInfo, isChatWithBot, isInStoryViewer),
|
() => getAllowedAttachmentOptions(chat,
|
||||||
[chat, chatFullInfo, isChatWithBot, isInStoryViewer],
|
chatFullInfo,
|
||||||
|
isChatWithBot,
|
||||||
|
isInStoryViewer,
|
||||||
|
paidMessagesStars,
|
||||||
|
isInScheduledList),
|
||||||
|
[chat, chatFullInfo, isChatWithBot, isInStoryViewer, paidMessagesStars, isInScheduledList],
|
||||||
);
|
);
|
||||||
|
|
||||||
const isNeedPremium = isContactRequirePremium && isInStoryViewer;
|
const isNeedPremium = isContactRequirePremium && isInStoryViewer;
|
||||||
@ -541,7 +550,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
shouldAutoApprove: shouldPaidMessageAutoApprove,
|
shouldAutoApprove: shouldPaidMessageAutoApprove,
|
||||||
setAutoApprove: setShouldPaidMessageAutoApprove,
|
setAutoApprove: setShouldPaidMessageAutoApprove,
|
||||||
handleWithConfirmation: handleActionWithPaymentConfirmation,
|
handleWithConfirmation: handleActionWithPaymentConfirmation,
|
||||||
} = usePaidMessageConfirmation(starsForAllMessages);
|
} = usePaidMessageConfirmation(starsForAllMessages, isStarsBalanceModalOpen, starsBalance);
|
||||||
|
|
||||||
const hasWebPagePreview = !hasAttachments && canAttachEmbedLinks && !noWebPage && Boolean(webPagePreview);
|
const hasWebPagePreview = !hasAttachments && canAttachEmbedLinks && !noWebPage && Boolean(webPagePreview);
|
||||||
const isComposerBlocked = isSendTextBlocked && !editingMessage;
|
const isComposerBlocked = isSendTextBlocked && !editingMessage;
|
||||||
@ -1391,19 +1400,23 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
if (isInScheduledList) {
|
if (isInScheduledList) {
|
||||||
requestCalendar((scheduledAt) => {
|
requestCalendar((scheduledAt) => {
|
||||||
handleMessageSchedule({ poll }, scheduledAt, currentMessageList);
|
handleActionWithPaymentConfirmation(
|
||||||
|
handleMessageSchedule,
|
||||||
|
{ poll },
|
||||||
|
scheduledAt,
|
||||||
|
currentMessageList,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
closePollModal();
|
closePollModal();
|
||||||
} else {
|
} else {
|
||||||
sendMessage({ messageList: currentMessageList, poll, isSilent: isSilentPosting });
|
handleActionWithPaymentConfirmation(
|
||||||
|
sendMessage,
|
||||||
|
{ messageList: currentMessageList, poll, isSilent: isSilentPosting },
|
||||||
|
);
|
||||||
closePollModal();
|
closePollModal();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const handlePollSendWithPaymentConfirmation = useLastCallback((poll: ApiNewPoll) => {
|
|
||||||
handleActionWithPaymentConfirmation(handlePollSend, poll);
|
|
||||||
});
|
|
||||||
|
|
||||||
const sendSilent = useLastCallback((additionalArgs?: ScheduledMessageArgs) => {
|
const sendSilent = useLastCallback((additionalArgs?: ScheduledMessageArgs) => {
|
||||||
if (isInScheduledList) {
|
if (isInScheduledList) {
|
||||||
requestCalendar((scheduledAt) => {
|
requestCalendar((scheduledAt) => {
|
||||||
@ -1587,7 +1600,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
message: oldLang('VoiceMessagesRestrictedByPrivacy', chat?.title),
|
message: oldLang('VoiceMessagesRestrictedByPrivacy', chat?.title),
|
||||||
});
|
});
|
||||||
} else if (!canSendVoices) {
|
} else if (!canSendVoices) {
|
||||||
showAllowedMessageTypesNotification({ chatId });
|
showAllowedMessageTypesNotification({ chatId, messageListType });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setIsViewOnceEnabled(false);
|
setIsViewOnceEnabled(false);
|
||||||
@ -1812,7 +1825,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
isQuiz={pollModal.isQuiz}
|
isQuiz={pollModal.isQuiz}
|
||||||
shouldBeAnonymous={isChannel}
|
shouldBeAnonymous={isChannel}
|
||||||
onClear={closePollModal}
|
onClear={closePollModal}
|
||||||
onSend={handlePollSendWithPaymentConfirmation}
|
onSend={handlePollSend}
|
||||||
/>
|
/>
|
||||||
<SendAsMenu
|
<SendAsMenu
|
||||||
isOpen={isSendAsMenuOpen}
|
isOpen={isSendAsMenuOpen}
|
||||||
@ -1998,6 +2011,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
onFocus={markInputHasFocus}
|
onFocus={markInputHasFocus}
|
||||||
onBlur={unmarkInputHasFocus}
|
onBlur={unmarkInputHasFocus}
|
||||||
isNeedPremium={isNeedPremium}
|
isNeedPremium={isNeedPremium}
|
||||||
|
messageListType={messageListType}
|
||||||
/>
|
/>
|
||||||
{isInMessageList && (
|
{isInMessageList && (
|
||||||
<>
|
<>
|
||||||
@ -2084,6 +2098,8 @@ const Composer: FC<OwnProps & StateProps> = ({
|
|||||||
theme={theme}
|
theme={theme}
|
||||||
onMenuOpen={onAttachMenuOpen}
|
onMenuOpen={onAttachMenuOpen}
|
||||||
onMenuClose={onAttachMenuClose}
|
onMenuClose={onAttachMenuClose}
|
||||||
|
messageListType={messageListType}
|
||||||
|
paidMessagesStars={paidMessagesStars}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{isInMessageList && Boolean(botKeyboardMessageId) && (
|
{isInMessageList && Boolean(botKeyboardMessageId) && (
|
||||||
@ -2354,6 +2370,8 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
|
|
||||||
const maxMessageLength = global.config?.maxMessageLength || DEFAULT_MAX_MESSAGE_LENGTH;
|
const maxMessageLength = global.config?.maxMessageLength || DEFAULT_MAX_MESSAGE_LENGTH;
|
||||||
const isForwarding = chatId === tabState.forwardMessages.toChatId;
|
const isForwarding = chatId === tabState.forwardMessages.toChatId;
|
||||||
|
const starsBalance = global.stars?.balance.amount || 0;
|
||||||
|
const isStarsBalanceModalOpen = Boolean(tabState.starsBalanceModal);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
availableReactions: global.reactions.availableReactions,
|
availableReactions: global.reactions.availableReactions,
|
||||||
@ -2436,6 +2454,8 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
shouldPaidMessageAutoApprove,
|
shouldPaidMessageAutoApprove,
|
||||||
isSilentPosting,
|
isSilentPosting,
|
||||||
isPaymentMessageConfirmDialogOpen: tabState.isPaymentMessageConfirmDialogOpen,
|
isPaymentMessageConfirmDialogOpen: tabState.isPaymentMessageConfirmDialogOpen,
|
||||||
|
starsBalance,
|
||||||
|
isStarsBalanceModalOpen,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(Composer));
|
)(Composer));
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import type { IRadioOption } from '../ui/CheckboxGroup';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
getHasAdminRight,
|
getHasAdminRight,
|
||||||
getPeerTitle,
|
|
||||||
getPrivateChatUserId,
|
getPrivateChatUserId,
|
||||||
getUserFirstOrLastName, isChatBasicGroup,
|
getUserFirstOrLastName, isChatBasicGroup,
|
||||||
isChatChannel,
|
isChatChannel,
|
||||||
@ -20,6 +19,7 @@ import {
|
|||||||
isSystemBot,
|
isSystemBot,
|
||||||
isUserId,
|
isUserId,
|
||||||
} from '../../global/helpers';
|
} from '../../global/helpers';
|
||||||
|
import { getPeerTitle } from '../../global/helpers/peers';
|
||||||
import {
|
import {
|
||||||
getSendersFromSelectedMessages,
|
getSendersFromSelectedMessages,
|
||||||
selectBot,
|
selectBot,
|
||||||
|
|||||||
@ -15,8 +15,8 @@ import {
|
|||||||
isAnonymousForwardsChat,
|
isAnonymousForwardsChat,
|
||||||
isChatWithRepliesBot,
|
isChatWithRepliesBot,
|
||||||
isChatWithVerificationCodesBot,
|
isChatWithVerificationCodesBot,
|
||||||
isPeerUser,
|
|
||||||
} from '../../global/helpers';
|
} from '../../global/helpers';
|
||||||
|
import { isApiPeerUser } from '../../global/helpers/peers';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import buildStyle from '../../util/buildStyle';
|
import buildStyle from '../../util/buildStyle';
|
||||||
import { copyTextToClipboard } from '../../util/clipboard';
|
import { copyTextToClipboard } from '../../util/clipboard';
|
||||||
@ -71,7 +71,7 @@ const FullNameTitle: FC<OwnProps> = ({
|
|||||||
const { showNotification } = getActions();
|
const { showNotification } = getActions();
|
||||||
const realPeer = 'id' in peer ? peer : undefined;
|
const realPeer = 'id' in peer ? peer : undefined;
|
||||||
const customPeer = 'isCustomPeer' in peer ? peer : undefined;
|
const customPeer = 'isCustomPeer' in peer ? peer : undefined;
|
||||||
const isUser = realPeer && isPeerUser(realPeer);
|
const isUser = realPeer && isApiPeerUser(realPeer);
|
||||||
const title = realPeer && (isUser ? getUserFullName(realPeer) : getChatTitle(lang, realPeer));
|
const title = realPeer && (isUser ? getUserFullName(realPeer) : getChatTitle(lang, realPeer));
|
||||||
const isPremium = isUser && realPeer.isPremium;
|
const isPremium = isUser && realPeer.isPremium;
|
||||||
const canShowEmojiStatus = withEmojiStatus && !isSavedMessages && realPeer;
|
const canShowEmojiStatus = withEmojiStatus && !isSavedMessages && realPeer;
|
||||||
|
|||||||
@ -6,8 +6,7 @@ import type { ApiPeer } from '../../api/types';
|
|||||||
import type { CustomPeer } from '../../types';
|
import type { CustomPeer } from '../../types';
|
||||||
import type { IconName } from '../../types/icons';
|
import type { IconName } from '../../types/icons';
|
||||||
|
|
||||||
import { getPeerTitle } from '../../global/helpers';
|
import { getPeerTitle, isApiPeerChat } from '../../global/helpers/peers';
|
||||||
import { isApiPeerChat } from '../../global/helpers/peers';
|
|
||||||
import { selectPeer, selectUser } from '../../global/selectors';
|
import { selectPeer, selectUser } from '../../global/selectors';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { getPeerColorClass } from './helpers/peerColor';
|
import { getPeerColorClass } from './helpers/peerColor';
|
||||||
|
|||||||
@ -14,13 +14,13 @@ import {
|
|||||||
getMessageIsSpoiler,
|
getMessageIsSpoiler,
|
||||||
getMessageMediaHash,
|
getMessageMediaHash,
|
||||||
getMessageRoundVideo,
|
getMessageRoundVideo,
|
||||||
getPeerTitle,
|
|
||||||
isChatChannel,
|
isChatChannel,
|
||||||
isChatGroup,
|
isChatGroup,
|
||||||
isMessageTranslatable,
|
isMessageTranslatable,
|
||||||
isUserId,
|
isUserId,
|
||||||
} from '../../../global/helpers';
|
} from '../../../global/helpers';
|
||||||
import { getMediaContentTypeDescription } from '../../../global/helpers/messageSummary';
|
import { getMediaContentTypeDescription } from '../../../global/helpers/messageSummary';
|
||||||
|
import { getPeerTitle } from '../../../global/helpers/peers';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import freezeWhenClosed from '../../../util/hoc/freezeWhenClosed';
|
import freezeWhenClosed from '../../../util/hoc/freezeWhenClosed';
|
||||||
import { getPictogramDimensions } from '../helpers/mediaDimensions';
|
import { getPictogramDimensions } from '../helpers/mediaDimensions';
|
||||||
|
|||||||
@ -6,9 +6,9 @@ import type { ApiPeer, ApiTypeStory } from '../../../api/types';
|
|||||||
import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
|
import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getPeerTitle,
|
|
||||||
getStoryMediaHash,
|
getStoryMediaHash,
|
||||||
} from '../../../global/helpers';
|
} from '../../../global/helpers';
|
||||||
|
import { getPeerTitle } from '../../../global/helpers/peers';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { getPictogramDimensions } from '../helpers/mediaDimensions';
|
import { getPictogramDimensions } from '../helpers/mediaDimensions';
|
||||||
import renderText from '../helpers/renderText';
|
import renderText from '../helpers/renderText';
|
||||||
|
|||||||
@ -10,9 +10,9 @@ import type {
|
|||||||
import type { IconName } from '../../../types/icons';
|
import type { IconName } from '../../../types/icons';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getPeerTitle,
|
|
||||||
isUserId,
|
isUserId,
|
||||||
} from '../../../global/helpers';
|
} from '../../../global/helpers';
|
||||||
|
import { getPeerTitle } from '../../../global/helpers/peers';
|
||||||
import { selectPeer, selectPeerStory } from '../../../global/selectors';
|
import { selectPeer, selectPeerStory } from '../../../global/selectors';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { getPeerColorClass } from '../helpers/peerColor';
|
import { getPeerColorClass } from '../helpers/peerColor';
|
||||||
|
|||||||
@ -15,10 +15,10 @@ import {
|
|||||||
getMessageMediaHash,
|
getMessageMediaHash,
|
||||||
getMessageMediaThumbDataUri,
|
getMessageMediaThumbDataUri,
|
||||||
getMessageRoundVideo,
|
getMessageRoundVideo,
|
||||||
getMessageSenderName,
|
|
||||||
getMessageSticker,
|
getMessageSticker,
|
||||||
getMessageVideo,
|
getMessageVideo,
|
||||||
} from '../../../../global/helpers';
|
} from '../../../../global/helpers';
|
||||||
|
import { getMessageSenderName } from '../../../../global/helpers/peers';
|
||||||
import buildClassName from '../../../../util/buildClassName';
|
import buildClassName from '../../../../util/buildClassName';
|
||||||
import renderText from '../../../common/helpers/renderText';
|
import renderText from '../../../common/helpers/renderText';
|
||||||
import { renderTextWithEntities } from '../../../common/helpers/renderTextWithEntities';
|
import { renderTextWithEntities } from '../../../common/helpers/renderTextWithEntities';
|
||||||
|
|||||||
@ -3,10 +3,10 @@ import type { OldLangFn } from '../../../../hooks/useOldLang';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
getChatTitle,
|
getChatTitle,
|
||||||
getPeerTitle,
|
|
||||||
isChatGroup,
|
isChatGroup,
|
||||||
isUserId,
|
isUserId,
|
||||||
} from '../../../../global/helpers';
|
} from '../../../../global/helpers';
|
||||||
|
import { getPeerTitle } from '../../../../global/helpers/peers';
|
||||||
|
|
||||||
export function getSenderName(
|
export function getSenderName(
|
||||||
lang: OldLangFn, message: ApiMessage, chatsById: Record<string, ApiChat>, usersById: Record<string, ApiUser>,
|
lang: OldLangFn, message: ApiMessage, chatsById: Record<string, ApiChat>, usersById: Record<string, ApiUser>,
|
||||||
|
|||||||
@ -10,3 +10,9 @@
|
|||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
color: var(--color-gray);
|
color: var(--color-gray);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.checked .lock-icon {
|
||||||
|
left: 1.25rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import React, { memo } from '../../../lib/teact/teact';
|
import React, { memo } from '../../../lib/teact/teact';
|
||||||
import { getActions } from '../../../global';
|
import { getActions } from '../../../global';
|
||||||
|
|
||||||
|
import buildClassName from '../../../util/buildClassName';
|
||||||
|
|
||||||
import useOldLang from '../../../hooks/useOldLang';
|
import useOldLang from '../../../hooks/useOldLang';
|
||||||
|
|
||||||
import Icon from '../../common/icons/Icon';
|
import Icon from '../../common/icons/Icon';
|
||||||
@ -9,15 +11,19 @@ import styles from './PrivacyLockedOption.module.scss';
|
|||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
label: string;
|
label: string;
|
||||||
|
isChecked?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
function PrivacyLockedOption({ label }: OwnProps) {
|
function PrivacyLockedOption({ label, isChecked }: OwnProps) {
|
||||||
const lang = useOldLang();
|
const lang = useOldLang();
|
||||||
const { showNotification } = getActions();
|
const { showNotification } = getActions();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={styles.root}
|
className={buildClassName(
|
||||||
|
styles.root,
|
||||||
|
isChecked && styles.checked,
|
||||||
|
)}
|
||||||
onClick={() => showNotification({ message: lang('OptionPremiumRequiredMessage') })}
|
onClick={() => showNotification({ message: lang('OptionPremiumRequiredMessage') })}
|
||||||
>
|
>
|
||||||
<span>{label}</span>
|
<span>{label}</span>
|
||||||
|
|||||||
@ -72,6 +72,12 @@ function PrivacyMessages({
|
|||||||
const canChangeChargeForMessages = isCurrentUserPremium && canChargeForMessages;
|
const canChangeChargeForMessages = isCurrentUserPremium && canChargeForMessages;
|
||||||
const [chargeForMessages, setChargeForMessages] = useState<number>(nonContactPeersPaidStars);
|
const [chargeForMessages, setChargeForMessages] = useState<number>(nonContactPeersPaidStars);
|
||||||
|
|
||||||
|
const selectedValue = useMemo(() => {
|
||||||
|
if (shouldChargeForMessages) return 'charge_for_messages';
|
||||||
|
if (shouldNewNonContactPeersRequirePremium) return 'contacts_and_premium';
|
||||||
|
return 'everybody';
|
||||||
|
}, [shouldChargeForMessages, shouldNewNonContactPeersRequirePremium]);
|
||||||
|
|
||||||
const options = useMemo(() => {
|
const options = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
{ value: 'everybody', label: oldLang('P2PEverybody') },
|
{ value: 'everybody', label: oldLang('P2PEverybody') },
|
||||||
@ -80,21 +86,29 @@ function PrivacyMessages({
|
|||||||
label: canChangeForContactsAndPremium ? (
|
label: canChangeForContactsAndPremium ? (
|
||||||
oldLang('PrivacyMessagesContactsAndPremium')
|
oldLang('PrivacyMessagesContactsAndPremium')
|
||||||
) : (
|
) : (
|
||||||
<PrivacyLockedOption label={oldLang('PrivacyMessagesContactsAndPremium')} />
|
<PrivacyLockedOption
|
||||||
|
label={oldLang('PrivacyMessagesContactsAndPremium')}
|
||||||
|
isChecked={selectedValue === 'contacts_and_premium'}
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
hidden: !canChangeForContactsAndPremium,
|
hidden: !canChangeForContactsAndPremium,
|
||||||
|
isCanCheckedInDisabled: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'charge_for_messages',
|
value: 'charge_for_messages',
|
||||||
label: canChangeChargeForMessages ? (
|
label: canChangeChargeForMessages ? (
|
||||||
lang('PrivacyChargeForMessages')
|
lang('PrivacyChargeForMessages')
|
||||||
) : (
|
) : (
|
||||||
<PrivacyLockedOption label={lang('PrivacyChargeForMessages')} />
|
<PrivacyLockedOption
|
||||||
|
label={lang('PrivacyChargeForMessages')}
|
||||||
|
isChecked={selectedValue === 'charge_for_messages'}
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
hidden: !canChangeChargeForMessages,
|
hidden: !canChangeChargeForMessages,
|
||||||
|
isCanCheckedInDisabled: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}, [oldLang, lang, canChangeForContactsAndPremium, canChangeChargeForMessages]);
|
}, [oldLang, lang, canChangeForContactsAndPremium, canChangeChargeForMessages, selectedValue]);
|
||||||
|
|
||||||
const handleChange = useLastCallback((privacy: string) => {
|
const handleChange = useLastCallback((privacy: string) => {
|
||||||
updateGlobalPrivacySettings({
|
updateGlobalPrivacySettings({
|
||||||
@ -184,12 +198,6 @@ function PrivacyMessages({
|
|||||||
onBack: onReset,
|
onBack: onReset,
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectedValue = useMemo(() => {
|
|
||||||
if (shouldChargeForMessages) return 'charge_for_messages';
|
|
||||||
if (shouldNewNonContactPeersRequirePremium) return 'contacts_and_premium';
|
|
||||||
return 'everybody';
|
|
||||||
}, [shouldChargeForMessages, shouldNewNonContactPeersRequirePremium]);
|
|
||||||
|
|
||||||
const privacyDescription = useMemo(() => {
|
const privacyDescription = useMemo(() => {
|
||||||
if (shouldChargeForMessages) return lang('PrivacyDescriptionChargeForMessages');
|
if (shouldChargeForMessages) return lang('PrivacyDescriptionChargeForMessages');
|
||||||
return lang('PrivacyDescriptionMessagesContactsAndPremium');
|
return lang('PrivacyDescriptionMessagesContactsAndPremium');
|
||||||
|
|||||||
@ -6,8 +6,9 @@ import type { ApiChat, ApiPeer } from '../../api/types';
|
|||||||
import type { MediaViewerItem } from './helpers/getViewableMedia';
|
import type { MediaViewerItem } from './helpers/getViewableMedia';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getPeerTitle, isChatChannel, isChatGroup, isUserId,
|
isChatChannel, isChatGroup, isUserId,
|
||||||
} from '../../global/helpers';
|
} from '../../global/helpers';
|
||||||
|
import { getPeerTitle } from '../../global/helpers/peers';
|
||||||
import {
|
import {
|
||||||
selectSender,
|
selectSender,
|
||||||
} from '../../global/selectors';
|
} from '../../global/selectors';
|
||||||
|
|||||||
@ -14,11 +14,11 @@ import { SCHEDULED_WHEN_ONLINE } from '../../config';
|
|||||||
import {
|
import {
|
||||||
getMessageHtmlId,
|
getMessageHtmlId,
|
||||||
getMessageOriginalId,
|
getMessageOriginalId,
|
||||||
getPeerTitle,
|
|
||||||
isActionMessage,
|
isActionMessage,
|
||||||
isOwnMessage,
|
isOwnMessage,
|
||||||
isServiceNotificationMessage,
|
isServiceNotificationMessage,
|
||||||
} from '../../global/helpers';
|
} from '../../global/helpers';
|
||||||
|
import { getPeerTitle } from '../../global/helpers/peers';
|
||||||
import { selectSender } from '../../global/selectors';
|
import { selectSender } from '../../global/selectors';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { formatHumanDate } from '../../util/dates/dateFormat';
|
import { formatHumanDate } from '../../util/dates/dateFormat';
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import React, {
|
|||||||
|
|
||||||
import type { ApiAttachMenuPeerType, ApiMessage } from '../../../api/types';
|
import type { ApiAttachMenuPeerType, ApiMessage } from '../../../api/types';
|
||||||
import type { GlobalState } from '../../../global/types';
|
import type { GlobalState } from '../../../global/types';
|
||||||
import type { ISettings, ThreadId } from '../../../types';
|
import type { ISettings, MessageListType, ThreadId } from '../../../types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CONTENT_TYPES_WITH_PREVIEW, DEBUG_LOG_FILENAME, SUPPORTED_AUDIO_CONTENT_TYPES,
|
CONTENT_TYPES_WITH_PREVIEW, DEBUG_LOG_FILENAME, SUPPORTED_AUDIO_CONTENT_TYPES,
|
||||||
@ -27,6 +27,7 @@ import { openSystemFilesDialog } from '../../../util/systemFilesDialog';
|
|||||||
import { IS_TOUCH_ENV } from '../../../util/windowEnvironment';
|
import { IS_TOUCH_ENV } from '../../../util/windowEnvironment';
|
||||||
|
|
||||||
import useFlag from '../../../hooks/useFlag';
|
import useFlag from '../../../hooks/useFlag';
|
||||||
|
import useLang from '../../../hooks/useLang';
|
||||||
import useLastCallback from '../../../hooks/useLastCallback';
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
import useMouseInside from '../../../hooks/useMouseInside';
|
import useMouseInside from '../../../hooks/useMouseInside';
|
||||||
import useOldLang from '../../../hooks/useOldLang';
|
import useOldLang from '../../../hooks/useOldLang';
|
||||||
@ -60,6 +61,8 @@ export type OwnProps = {
|
|||||||
onMenuClose: NoneToVoidFunction;
|
onMenuClose: NoneToVoidFunction;
|
||||||
canEditMedia?: boolean;
|
canEditMedia?: boolean;
|
||||||
editingMessage?: ApiMessage;
|
editingMessage?: ApiMessage;
|
||||||
|
messageListType?: MessageListType;
|
||||||
|
paidMessagesStars?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
const AttachMenu: FC<OwnProps> = ({
|
const AttachMenu: FC<OwnProps> = ({
|
||||||
@ -83,6 +86,8 @@ const AttachMenu: FC<OwnProps> = ({
|
|||||||
onPollCreate,
|
onPollCreate,
|
||||||
canEditMedia,
|
canEditMedia,
|
||||||
editingMessage,
|
editingMessage,
|
||||||
|
messageListType,
|
||||||
|
paidMessagesStars,
|
||||||
}) => {
|
}) => {
|
||||||
const [isAttachMenuOpen, openAttachMenu, closeAttachMenu] = useFlag();
|
const [isAttachMenuOpen, openAttachMenu, closeAttachMenu] = useFlag();
|
||||||
const [handleMouseEnter, handleMouseLeave, markMouseInside] = useMouseInside(isAttachMenuOpen, closeAttachMenu);
|
const [handleMouseEnter, handleMouseLeave, markMouseInside] = useMouseInside(isAttachMenuOpen, closeAttachMenu);
|
||||||
@ -164,7 +169,8 @@ const AttachMenu: FC<OwnProps> = ({
|
|||||||
: undefined;
|
: undefined;
|
||||||
}, [attachBots, chatId, peerType]);
|
}, [attachBots, chatId, peerType]);
|
||||||
|
|
||||||
const lang = useOldLang();
|
const oldLang = useOldLang();
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
if (!isButtonVisible) {
|
if (!isButtonVisible) {
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -221,31 +227,35 @@ const AttachMenu: FC<OwnProps> = ({
|
|||||||
** transferring to the fragment content in the second clause
|
** transferring to the fragment content in the second clause
|
||||||
*/}
|
*/}
|
||||||
{!canAttachMedia && (
|
{!canAttachMedia && (
|
||||||
<MenuItem className="media-disabled" disabled>Posting media content is not allowed in this group.</MenuItem>
|
<MenuItem className="media-disabled" disabled>
|
||||||
|
{lang(messageListType === 'scheduled' && paidMessagesStars
|
||||||
|
? 'DescriptionScheduledPaidMediaNotAllowed'
|
||||||
|
: 'DescriptionRestrictedMedia')}
|
||||||
|
</MenuItem>
|
||||||
)}
|
)}
|
||||||
{canAttachMedia && (
|
{canAttachMedia && (
|
||||||
<>
|
<>
|
||||||
{canSendVideoOrPhoto && !isFile && (
|
{canSendVideoOrPhoto && !isFile && (
|
||||||
<MenuItem icon="photo" onClick={handleQuickSelect}>
|
<MenuItem icon="photo" onClick={handleQuickSelect}>
|
||||||
{lang(canSendVideoAndPhoto ? 'AttachmentMenu.PhotoOrVideo'
|
{oldLang(canSendVideoAndPhoto ? 'AttachmentMenu.PhotoOrVideo'
|
||||||
: (canSendPhotos ? 'InputAttach.Popover.Photo' : 'InputAttach.Popover.Video'))}
|
: (canSendPhotos ? 'InputAttach.Popover.Photo' : 'InputAttach.Popover.Video'))}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
)}
|
||||||
{((canSendDocuments || canSendAudios) && !isPhotoOrVideo)
|
{((canSendDocuments || canSendAudios) && !isPhotoOrVideo)
|
||||||
&& (
|
&& (
|
||||||
<MenuItem icon="document" onClick={handleDocumentSelect}>
|
<MenuItem icon="document" onClick={handleDocumentSelect}>
|
||||||
{lang(!canSendDocuments && canSendAudios ? 'InputAttach.Popover.Music' : 'AttachDocument')}
|
{oldLang(!canSendDocuments && canSendAudios ? 'InputAttach.Popover.Music' : 'AttachDocument')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
)}
|
||||||
{canSendDocuments && shouldCollectDebugLogs && (
|
{canSendDocuments && shouldCollectDebugLogs && (
|
||||||
<MenuItem icon="bug" onClick={handleSendLogs}>
|
<MenuItem icon="bug" onClick={handleSendLogs}>
|
||||||
{lang('DebugSendLogs')}
|
{oldLang('DebugSendLogs')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{canAttachPolls && !editingMessage && (
|
{canAttachPolls && !editingMessage && (
|
||||||
<MenuItem icon="poll" onClick={onPollCreate}>{lang('Poll')}</MenuItem>
|
<MenuItem icon="poll" onClick={onPollCreate}>{oldLang('Poll')}</MenuItem>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!editingMessage && !canEditMedia && !isScheduled && bots?.map((bot) => (
|
{!editingMessage && !canEditMedia && !isScheduled && bots?.map((bot) => (
|
||||||
|
|||||||
@ -8,7 +8,9 @@ import React, {
|
|||||||
import { getActions, withGlobal } from '../../../global';
|
import { getActions, withGlobal } from '../../../global';
|
||||||
|
|
||||||
import type { ApiInputMessageReplyInfo } from '../../../api/types';
|
import type { ApiInputMessageReplyInfo } from '../../../api/types';
|
||||||
import type { IAnchorPosition, ISettings, ThreadId } from '../../../types';
|
import type {
|
||||||
|
IAnchorPosition, ISettings, MessageListType, ThreadId,
|
||||||
|
} from '../../../types';
|
||||||
import type { Signal } from '../../../util/signals';
|
import type { Signal } from '../../../util/signals';
|
||||||
|
|
||||||
import { EDITABLE_INPUT_ID } from '../../../config';
|
import { EDITABLE_INPUT_ID } from '../../../config';
|
||||||
@ -75,6 +77,7 @@ type OwnProps = {
|
|||||||
onFocus?: NoneToVoidFunction;
|
onFocus?: NoneToVoidFunction;
|
||||||
onBlur?: NoneToVoidFunction;
|
onBlur?: NoneToVoidFunction;
|
||||||
isNeedPremium?: boolean;
|
isNeedPremium?: boolean;
|
||||||
|
messageListType?: MessageListType;
|
||||||
};
|
};
|
||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
@ -141,6 +144,7 @@ const MessageInput: FC<OwnProps & StateProps> = ({
|
|||||||
onFocus,
|
onFocus,
|
||||||
onBlur,
|
onBlur,
|
||||||
isNeedPremium,
|
isNeedPremium,
|
||||||
|
messageListType,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
editLastMessage,
|
editLastMessage,
|
||||||
@ -456,7 +460,7 @@ const MessageInput: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
function handleClick() {
|
function handleClick() {
|
||||||
if (isAttachmentModalInput || canSendPlainText || (isStoryInput && isNeedPremium)) return;
|
if (isAttachmentModalInput || canSendPlainText || (isStoryInput && isNeedPremium)) return;
|
||||||
showAllowedMessageTypesNotification({ chatId });
|
showAllowedMessageTypesNotification({ chatId, messageListType });
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleOpenPremiumModal = useLastCallback(() => openPremiumModal());
|
const handleOpenPremiumModal = useLastCallback(() => openPremiumModal());
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useRef, useState } from '../../../../lib/teact/teact';
|
import { useEffect, useRef, useState } from '../../../../lib/teact/teact';
|
||||||
import { getActions, getGlobal } from '../../../../global';
|
import { getActions, getGlobal } from '../../../../global';
|
||||||
|
|
||||||
import { PAID_MESSAGES_PURPOSE } from '../../../../config';
|
import { PAID_MESSAGES_PURPOSE } from '../../../../config';
|
||||||
@ -7,6 +7,8 @@ import useLastCallback from '../../../../hooks/useLastCallback';
|
|||||||
|
|
||||||
export default function usePaidMessageConfirmation(
|
export default function usePaidMessageConfirmation(
|
||||||
starsForAllMessages: number,
|
starsForAllMessages: number,
|
||||||
|
isStarsBalanceModeOpen: boolean,
|
||||||
|
starsBalance: number,
|
||||||
) {
|
) {
|
||||||
const {
|
const {
|
||||||
shouldPaidMessageAutoApprove,
|
shouldPaidMessageAutoApprove,
|
||||||
@ -14,41 +16,63 @@ export default function usePaidMessageConfirmation(
|
|||||||
|
|
||||||
const [shouldAutoApprove,
|
const [shouldAutoApprove,
|
||||||
setAutoApprove] = useState(Boolean(shouldPaidMessageAutoApprove));
|
setAutoApprove] = useState(Boolean(shouldPaidMessageAutoApprove));
|
||||||
|
const [isWaitingStarsTopup, setIsWaitingStarsTopup] = useState(false);
|
||||||
const confirmPaymentHandlerRef = useRef<NoneToVoidFunction | undefined>(undefined);
|
const confirmPaymentHandlerRef = useRef<NoneToVoidFunction | undefined>(undefined);
|
||||||
|
|
||||||
const closeConfirmDialog = useLastCallback(() => {
|
const closeConfirmDialog = useLastCallback(() => {
|
||||||
getActions().closePaymentMessageConfirmDialogOpen();
|
getActions().closePaymentMessageConfirmDialogOpen();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isWaitingStarsTopup && !isStarsBalanceModeOpen) {
|
||||||
|
setIsWaitingStarsTopup(false);
|
||||||
|
|
||||||
|
if (starsBalance > starsForAllMessages) {
|
||||||
|
confirmPaymentHandlerRef?.current?.();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [isWaitingStarsTopup, isStarsBalanceModeOpen, starsBalance, starsForAllMessages]);
|
||||||
|
|
||||||
|
const handleStarsTopup = useLastCallback(() => {
|
||||||
|
getActions().openStarsBalanceModal({
|
||||||
|
topup: {
|
||||||
|
balanceNeeded: starsForAllMessages,
|
||||||
|
purpose: PAID_MESSAGES_PURPOSE,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
setIsWaitingStarsTopup(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
const dialogHandler = useLastCallback(() => {
|
||||||
|
if (starsForAllMessages > starsBalance) {
|
||||||
|
handleStarsTopup();
|
||||||
|
} else {
|
||||||
|
confirmPaymentHandlerRef?.current?.();
|
||||||
|
}
|
||||||
|
getActions().closePaymentMessageConfirmDialogOpen();
|
||||||
|
if (shouldAutoApprove) getActions().setPaidMessageAutoApprove();
|
||||||
|
});
|
||||||
|
|
||||||
const handleWithConfirmation = <T extends (...args: any[]) => void>(
|
const handleWithConfirmation = <T extends (...args: any[]) => void>(
|
||||||
handler: T,
|
handler: T,
|
||||||
...args: Parameters<T>
|
...args: Parameters<T>
|
||||||
) => {
|
) => {
|
||||||
if (starsForAllMessages) {
|
if (starsForAllMessages) {
|
||||||
const balance = getGlobal().stars?.balance.amount;
|
confirmPaymentHandlerRef.current = () => handler(...args);
|
||||||
if (balance && starsForAllMessages > balance) {
|
if (!shouldPaidMessageAutoApprove) {
|
||||||
getActions().openStarsBalanceModal({
|
getActions().openPaymentMessageConfirmDialogOpen();
|
||||||
topup:
|
return;
|
||||||
{ balanceNeeded: starsForAllMessages, purpose: PAID_MESSAGES_PURPOSE },
|
}
|
||||||
});
|
|
||||||
|
if (starsForAllMessages > starsBalance) {
|
||||||
|
handleStarsTopup();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!shouldPaidMessageAutoApprove && starsForAllMessages) {
|
handler(...args);
|
||||||
confirmPaymentHandlerRef.current = () => handler(...args);
|
|
||||||
getActions().openPaymentMessageConfirmDialogOpen();
|
|
||||||
} else {
|
|
||||||
handler(...args);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const dialogHandler = useLastCallback(() => {
|
|
||||||
confirmPaymentHandlerRef.current?.();
|
|
||||||
getActions().closePaymentMessageConfirmDialogOpen();
|
|
||||||
if (shouldAutoApprove) getActions().setPaidMessageAutoApprove();
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
closeConfirmDialog,
|
closeConfirmDialog,
|
||||||
handleWithConfirmation,
|
handleWithConfirmation,
|
||||||
|
|||||||
@ -5,8 +5,9 @@ import type { ApiChat, ApiMessage, ApiPeer } from '../../../api/types';
|
|||||||
|
|
||||||
import { GENERAL_TOPIC_ID, SERVICE_NOTIFICATIONS_USER_ID, TME_LINK_PREFIX } from '../../../config';
|
import { GENERAL_TOPIC_ID, SERVICE_NOTIFICATIONS_USER_ID, TME_LINK_PREFIX } from '../../../config';
|
||||||
import {
|
import {
|
||||||
getMessageInvoice, getMessageText, getPeerTitle, isChatChannel,
|
getMessageInvoice, getMessageText, isChatChannel,
|
||||||
} from '../../../global/helpers';
|
} from '../../../global/helpers';
|
||||||
|
import { getPeerTitle } from '../../../global/helpers/peers';
|
||||||
import { getMessageReplyInfo } from '../../../global/helpers/replies';
|
import { getMessageReplyInfo } from '../../../global/helpers/replies';
|
||||||
import {
|
import {
|
||||||
selectChat,
|
selectChat,
|
||||||
|
|||||||
@ -53,7 +53,6 @@ import {
|
|||||||
getMessageHtmlId,
|
getMessageHtmlId,
|
||||||
getMessageSingleCustomEmoji,
|
getMessageSingleCustomEmoji,
|
||||||
getMessageSingleRegularEmoji,
|
getMessageSingleRegularEmoji,
|
||||||
getPeerFullTitle,
|
|
||||||
hasMessageText,
|
hasMessageText,
|
||||||
hasMessageTtl,
|
hasMessageTtl,
|
||||||
isAnonymousForwardsChat,
|
isAnonymousForwardsChat,
|
||||||
@ -69,6 +68,7 @@ import {
|
|||||||
isSystemBot,
|
isSystemBot,
|
||||||
isUserId,
|
isUserId,
|
||||||
} from '../../../global/helpers';
|
} from '../../../global/helpers';
|
||||||
|
import { getPeerFullTitle } from '../../../global/helpers/peers';
|
||||||
import { getMessageReplyInfo, getStoryReplyInfo } from '../../../global/helpers/replies';
|
import { getMessageReplyInfo, getStoryReplyInfo } from '../../../global/helpers/replies';
|
||||||
import {
|
import {
|
||||||
selectActiveDownloads,
|
selectActiveDownloads,
|
||||||
|
|||||||
@ -5,7 +5,8 @@ import type {
|
|||||||
ApiMessage, ApiPeer, ApiTypeStory, ApiUser,
|
ApiMessage, ApiPeer, ApiTypeStory, ApiUser,
|
||||||
} from '../../../api/types';
|
} from '../../../api/types';
|
||||||
|
|
||||||
import { getPeerTitle, getStoryMediaHash, getUserFirstOrLastName } from '../../../global/helpers';
|
import { getStoryMediaHash, getUserFirstOrLastName } from '../../../global/helpers';
|
||||||
|
import { getPeerTitle } from '../../../global/helpers/peers';
|
||||||
import {
|
import {
|
||||||
selectPeer,
|
selectPeer,
|
||||||
selectPeerStories,
|
selectPeerStories,
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { withGlobal } from '../../../../global';
|
|||||||
import type { ApiChat, ApiSticker } from '../../../../api/types';
|
import type { ApiChat, ApiSticker } from '../../../../api/types';
|
||||||
import type { ApiMessageActionGiftCode, ApiMessageActionPrizeStars } from '../../../../api/types/messageActions';
|
import type { ApiMessageActionGiftCode, ApiMessageActionPrizeStars } from '../../../../api/types/messageActions';
|
||||||
|
|
||||||
import { getPeerTitle } from '../../../../global/helpers';
|
import { getPeerTitle } from '../../../../global/helpers/peers';
|
||||||
import {
|
import {
|
||||||
selectCanPlayAnimatedEmojis,
|
selectCanPlayAnimatedEmojis,
|
||||||
selectChat,
|
selectChat,
|
||||||
|
|||||||
@ -4,8 +4,8 @@ import { withGlobal } from '../../../../global';
|
|||||||
import type { ApiMessage, ApiPeer } from '../../../../api/types';
|
import type { ApiMessage, ApiPeer } from '../../../../api/types';
|
||||||
import type { ApiMessageActionStarGift } from '../../../../api/types/messageActions';
|
import type { ApiMessageActionStarGift } from '../../../../api/types/messageActions';
|
||||||
|
|
||||||
import { getPeerTitle, isChatChannel } from '../../../../global/helpers';
|
import { isChatChannel } from '../../../../global/helpers';
|
||||||
import { isApiPeerChat } from '../../../../global/helpers/peers';
|
import { getPeerTitle, isApiPeerChat } from '../../../../global/helpers/peers';
|
||||||
import {
|
import {
|
||||||
selectCanPlayAnimatedEmojis,
|
selectCanPlayAnimatedEmojis,
|
||||||
selectPeer,
|
selectPeer,
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { withGlobal } from '../../../../global';
|
|||||||
import type { ApiMessage, ApiPeer } from '../../../../api/types';
|
import type { ApiMessage, ApiPeer } from '../../../../api/types';
|
||||||
import type { ApiMessageActionStarGiftUnique } from '../../../../api/types/messageActions';
|
import type { ApiMessageActionStarGiftUnique } from '../../../../api/types/messageActions';
|
||||||
|
|
||||||
import { getPeerTitle } from '../../../../global/helpers';
|
import { getPeerTitle } from '../../../../global/helpers/peers';
|
||||||
import {
|
import {
|
||||||
selectCanPlayAnimatedEmojis,
|
selectCanPlayAnimatedEmojis,
|
||||||
selectPeer,
|
selectPeer,
|
||||||
|
|||||||
@ -5,7 +5,8 @@ import type { ApiMessageActionSuggestProfilePhoto } from '../../../../api/types/
|
|||||||
import { type ApiMessage, type ApiPeer, MAIN_THREAD_ID } from '../../../../api/types';
|
import { type ApiMessage, type ApiPeer, MAIN_THREAD_ID } from '../../../../api/types';
|
||||||
import { MediaViewerOrigin, SettingsScreens } from '../../../../types';
|
import { MediaViewerOrigin, SettingsScreens } from '../../../../types';
|
||||||
|
|
||||||
import { getPeerTitle, getPhotoMediaHash, getVideoProfilePhotoMediaHash } from '../../../../global/helpers';
|
import { getPhotoMediaHash, getVideoProfilePhotoMediaHash } from '../../../../global/helpers';
|
||||||
|
import { getPeerTitle } from '../../../../global/helpers/peers';
|
||||||
import { selectPeer } from '../../../../global/selectors';
|
import { selectPeer } from '../../../../global/selectors';
|
||||||
import { fetchBlob } from '../../../../util/files';
|
import { fetchBlob } from '../../../../util/files';
|
||||||
import { renderPeerLink } from '../helpers/messageActions';
|
import { renderPeerLink } from '../helpers/messageActions';
|
||||||
|
|||||||
@ -10,8 +10,9 @@ import type { IconName } from '../../../types/icons';
|
|||||||
|
|
||||||
import { PLAYBACK_RATE_FOR_AUDIO_MIN_DURATION } from '../../../config';
|
import { PLAYBACK_RATE_FOR_AUDIO_MIN_DURATION } from '../../../config';
|
||||||
import {
|
import {
|
||||||
getMediaDuration, getMessageContent, getMessageMediaHash, getPeerTitle, isMessageLocal,
|
getMediaDuration, getMessageContent, getMessageMediaHash, isMessageLocal,
|
||||||
} from '../../../global/helpers';
|
} from '../../../global/helpers';
|
||||||
|
import { getPeerTitle } from '../../../global/helpers/peers';
|
||||||
import {
|
import {
|
||||||
selectChat, selectChatMessage, selectSender, selectTabState,
|
selectChat, selectChatMessage, selectSender, selectTabState,
|
||||||
} from '../../../global/selectors';
|
} from '../../../global/selectors';
|
||||||
|
|||||||
@ -12,8 +12,8 @@ import {
|
|||||||
getMessageMediaHash,
|
getMessageMediaHash,
|
||||||
getMessageSingleInlineButton,
|
getMessageSingleInlineButton,
|
||||||
getMessageVideo,
|
getMessageVideo,
|
||||||
getPeerTitle,
|
|
||||||
} from '../../../global/helpers';
|
} from '../../../global/helpers';
|
||||||
|
import { getPeerTitle } from '../../../global/helpers/peers';
|
||||||
import {
|
import {
|
||||||
selectAllowedMessageActionsSlow,
|
selectAllowedMessageActionsSlow,
|
||||||
selectChat,
|
selectChat,
|
||||||
|
|||||||
@ -33,9 +33,3 @@
|
|||||||
margin-inline-start: 0 !important;
|
margin-inline-start: 0 !important;
|
||||||
margin-inline-end: 0.125rem !important;
|
margin-inline-end: 0.125rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkBox {
|
|
||||||
margin-top: 0.375rem;
|
|
||||||
margin-inline: -1.125rem;
|
|
||||||
padding-inline-start: 3.5rem;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -7,23 +7,20 @@ import type {
|
|||||||
} from '../../../api/types';
|
} from '../../../api/types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getPeerTitle,
|
|
||||||
} from '../../../global/helpers';
|
} from '../../../global/helpers';
|
||||||
|
import { getPeerTitle } from '../../../global/helpers/peers';
|
||||||
import {
|
import {
|
||||||
selectChat,
|
selectChat,
|
||||||
selectUserFullInfo,
|
selectUserFullInfo,
|
||||||
} from '../../../global/selectors';
|
} from '../../../global/selectors';
|
||||||
import { formatStarsAsIcon } from '../../../util/localization/format';
|
import { formatStarsAsIcon } from '../../../util/localization/format';
|
||||||
|
|
||||||
import useFlag from '../../../hooks/useFlag';
|
|
||||||
import useLang from '../../../hooks/useLang';
|
import useLang from '../../../hooks/useLang';
|
||||||
// import useTimeout from '../../../hooks/schedulers/useTimeout';
|
// import useTimeout from '../../../hooks/schedulers/useTimeout';
|
||||||
import useLastCallback from '../../../hooks/useLastCallback';
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
import useHeaderPane, { type PaneState } from '../hooks/useHeaderPane';
|
import useHeaderPane, { type PaneState } from '../hooks/useHeaderPane';
|
||||||
|
|
||||||
import Button from '../../ui/Button';
|
import Button from '../../ui/Button';
|
||||||
import Checkbox from '../../ui/Checkbox';
|
|
||||||
import ConfirmDialog from '../../ui/ConfirmDialog';
|
|
||||||
|
|
||||||
// import CustomEmoji from '../../common/CustomEmoji';
|
// import CustomEmoji from '../../common/CustomEmoji';
|
||||||
import styles from './PaidMessageChargePane.module.scss';
|
import styles from './PaidMessageChargePane.module.scss';
|
||||||
@ -41,16 +38,14 @@ type StateProps = {
|
|||||||
const PaidMessageChargePane: FC<OwnProps & StateProps> = ({
|
const PaidMessageChargePane: FC<OwnProps & StateProps> = ({
|
||||||
chargedPaidMessageStars,
|
chargedPaidMessageStars,
|
||||||
chat,
|
chat,
|
||||||
onPaneStateChange,
|
|
||||||
peerId,
|
peerId,
|
||||||
|
onPaneStateChange,
|
||||||
}) => {
|
}) => {
|
||||||
const isOpen = Boolean(chargedPaidMessageStars);
|
const isOpen = Boolean(chargedPaidMessageStars);
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
const [isRemoveFeeDialogOpen, openRemoveFeeDialog, closeRemoveFeeDialog] = useFlag();
|
|
||||||
const [shouldRefoundStars, setShouldRefoundStars] = useFlag(false);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
addNoPaidMessagesException,
|
openChatRefundModal,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
const { ref, shouldRender } = useHeaderPane({
|
const { ref, shouldRender } = useHeaderPane({
|
||||||
@ -58,12 +53,8 @@ const PaidMessageChargePane: FC<OwnProps & StateProps> = ({
|
|||||||
onStateChange: onPaneStateChange,
|
onStateChange: onPaneStateChange,
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleRemoveFee = useLastCallback(() => {
|
const handleRefund = useLastCallback(() => {
|
||||||
openRemoveFeeDialog();
|
openChatRefundModal({ userId: peerId });
|
||||||
});
|
|
||||||
|
|
||||||
const handleConfirmRemoveFee = useLastCallback(() => {
|
|
||||||
addNoPaidMessagesException({ userId: peerId, shouldRefundCharged: shouldRefoundStars });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!shouldRender || !chargedPaidMessageStars) return undefined;
|
if (!shouldRender || !chargedPaidMessageStars) return undefined;
|
||||||
@ -80,20 +71,6 @@ const PaidMessageChargePane: FC<OwnProps & StateProps> = ({
|
|||||||
withNodes: true,
|
withNodes: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const dialogMessage = lang('ConfirmDialogMessageRemoveFee', {
|
|
||||||
peer: peerName,
|
|
||||||
}, {
|
|
||||||
withMarkdown: true,
|
|
||||||
withNodes: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const checkBoxTitle = lang('ConfirmDialogRemoveFeeRefundStars', {
|
|
||||||
amount: chargedPaidMessageStars,
|
|
||||||
}, {
|
|
||||||
withMarkdown: true,
|
|
||||||
withNodes: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={ref} className={styles.root}>
|
<div ref={ref} className={styles.root}>
|
||||||
<div className={styles.message}>
|
<div className={styles.message}>
|
||||||
@ -106,26 +83,10 @@ const PaidMessageChargePane: FC<OwnProps & StateProps> = ({
|
|||||||
fluid
|
fluid
|
||||||
size="tiny"
|
size="tiny"
|
||||||
className={styles.button}
|
className={styles.button}
|
||||||
onClick={handleRemoveFee}
|
onClick={handleRefund}
|
||||||
>
|
>
|
||||||
{lang('RemoveFeeTitle')}
|
{lang('RemoveFeeTitle')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<ConfirmDialog
|
|
||||||
isOpen={isRemoveFeeDialogOpen}
|
|
||||||
onClose={closeRemoveFeeDialog}
|
|
||||||
title={lang('RemoveFeeTitle')}
|
|
||||||
confirmLabel={lang('ConfirmRemoveMessageFee')}
|
|
||||||
confirmHandler={handleConfirmRemoveFee}
|
|
||||||
>
|
|
||||||
{dialogMessage}
|
|
||||||
<Checkbox
|
|
||||||
className={styles.checkBox}
|
|
||||||
label={checkBoxTitle}
|
|
||||||
checked={shouldRefoundStars}
|
|
||||||
onCheck={setShouldRefoundStars}
|
|
||||||
/>
|
|
||||||
</ConfirmDialog>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import React, { memo } from '../../../lib/teact/teact';
|
|||||||
|
|
||||||
import type { ApiChat, ApiMessage, ApiPeer } from '../../../api/types';
|
import type { ApiChat, ApiMessage, ApiPeer } from '../../../api/types';
|
||||||
|
|
||||||
import { getMessageSenderName } from '../../../global/helpers';
|
import { getMessageSenderName } from '../../../global/helpers/peers';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import renderText from '../../common/helpers/renderText';
|
import renderText from '../../common/helpers/renderText';
|
||||||
|
|
||||||
|
|||||||
@ -32,6 +32,7 @@ import PreparedMessageModal from './preparedMessage/PreparedMessageModal.async';
|
|||||||
import ReportAdModal from './reportAd/ReportAdModal.async';
|
import ReportAdModal from './reportAd/ReportAdModal.async';
|
||||||
import ReportModal from './reportModal/ReportModal.async';
|
import ReportModal from './reportModal/ReportModal.async';
|
||||||
import SharePreparedMessageModal from './sharePreparedMessage/SharePreparedMessageModal.async';
|
import SharePreparedMessageModal from './sharePreparedMessage/SharePreparedMessageModal.async';
|
||||||
|
import ChatRefundModal from './stars/chatRefund/ChatRefundModal.async';
|
||||||
import StarsGiftModal from './stars/gift/StarsGiftModal.async';
|
import StarsGiftModal from './stars/gift/StarsGiftModal.async';
|
||||||
import StarsBalanceModal from './stars/StarsBalanceModal.async';
|
import StarsBalanceModal from './stars/StarsBalanceModal.async';
|
||||||
import StarsPaymentModal from './stars/StarsPaymentModal.async';
|
import StarsPaymentModal from './stars/StarsPaymentModal.async';
|
||||||
@ -77,7 +78,8 @@ type ModalKey = keyof Pick<TabState,
|
|||||||
'preparedMessageModal' |
|
'preparedMessageModal' |
|
||||||
'sharePreparedMessageModal' |
|
'sharePreparedMessageModal' |
|
||||||
'giftStatusInfoModal' |
|
'giftStatusInfoModal' |
|
||||||
'giftTransferModal'
|
'giftTransferModal' |
|
||||||
|
'chatRefundModal'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
@ -127,6 +129,7 @@ const MODALS: ModalRegistry = {
|
|||||||
preparedMessageModal: PreparedMessageModal,
|
preparedMessageModal: PreparedMessageModal,
|
||||||
sharePreparedMessageModal: SharePreparedMessageModal,
|
sharePreparedMessageModal: SharePreparedMessageModal,
|
||||||
giftTransferModal: GiftTransferModal,
|
giftTransferModal: GiftTransferModal,
|
||||||
|
chatRefundModal: ChatRefundModal,
|
||||||
};
|
};
|
||||||
const MODAL_KEYS = Object.keys(MODALS) as ModalKey[];
|
const MODAL_KEYS = Object.keys(MODALS) as ModalKey[];
|
||||||
const MODAL_ENTRIES = Object.entries(MODALS) as Entries<ModalRegistry>;
|
const MODAL_ENTRIES = Object.entries(MODALS) as Entries<ModalRegistry>;
|
||||||
|
|||||||
@ -11,9 +11,8 @@ import {
|
|||||||
} from '../../../api/types';
|
} from '../../../api/types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getPeerTitle,
|
|
||||||
} from '../../../global/helpers';
|
} from '../../../global/helpers';
|
||||||
import { isApiPeerUser } from '../../../global/helpers/peers';
|
import { getPeerTitle, isApiPeerUser } from '../../../global/helpers/peers';
|
||||||
import {
|
import {
|
||||||
selectPeer, selectPeerPaidMessagesStars,
|
selectPeer, selectPeerPaidMessagesStars,
|
||||||
selectTabState, selectTheme,
|
selectTabState, selectTheme,
|
||||||
|
|||||||
@ -14,8 +14,8 @@ import type { TabState } from '../../../global/types';
|
|||||||
import type { StarGiftCategory } from '../../../types';
|
import type { StarGiftCategory } from '../../../types';
|
||||||
|
|
||||||
import { STARS_CURRENCY_CODE } from '../../../config';
|
import { STARS_CURRENCY_CODE } from '../../../config';
|
||||||
import { getPeerTitle, getUserFullName } from '../../../global/helpers';
|
import { getUserFullName } from '../../../global/helpers';
|
||||||
import { isApiPeerChat, isApiPeerUser } from '../../../global/helpers/peers';
|
import { getPeerTitle, isApiPeerChat, isApiPeerUser } from '../../../global/helpers/peers';
|
||||||
import { selectPeer } from '../../../global/selectors';
|
import { selectPeer } from '../../../global/selectors';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { throttle } from '../../../util/schedulers';
|
import { throttle } from '../../../util/schedulers';
|
||||||
|
|||||||
@ -8,8 +8,8 @@ import type {
|
|||||||
} from '../../../../api/types';
|
} from '../../../../api/types';
|
||||||
import type { TabState } from '../../../../global/types';
|
import type { TabState } from '../../../../global/types';
|
||||||
|
|
||||||
import { getHasAdminRight, getPeerTitle } from '../../../../global/helpers';
|
import { getHasAdminRight } from '../../../../global/helpers';
|
||||||
import { isApiPeerChat } from '../../../../global/helpers/peers';
|
import { getPeerTitle, isApiPeerChat } from '../../../../global/helpers/peers';
|
||||||
import { selectPeer, selectUser } from '../../../../global/selectors';
|
import { selectPeer, selectUser } from '../../../../global/selectors';
|
||||||
import buildClassName from '../../../../util/buildClassName';
|
import buildClassName from '../../../../util/buildClassName';
|
||||||
import { copyTextToClipboard } from '../../../../util/clipboard';
|
import { copyTextToClipboard } from '../../../../util/clipboard';
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import type { TabState } from '../../../../global/types';
|
|||||||
import type { UniqueCustomPeer } from '../../../../types';
|
import type { UniqueCustomPeer } from '../../../../types';
|
||||||
|
|
||||||
import { ALL_FOLDER_ID } from '../../../../config';
|
import { ALL_FOLDER_ID } from '../../../../config';
|
||||||
import { getPeerTitle } from '../../../../global/helpers';
|
import { getPeerTitle } from '../../../../global/helpers/peers';
|
||||||
import { selectCanGift, selectPeer } from '../../../../global/selectors';
|
import { selectCanGift, selectPeer } from '../../../../global/selectors';
|
||||||
import { unique } from '../../../../util/iteratees';
|
import { unique } from '../../../../util/iteratees';
|
||||||
import { formatStarsAsIcon, formatStarsAsText } from '../../../../util/localization/format';
|
import { formatStarsAsIcon, formatStarsAsText } from '../../../../util/localization/format';
|
||||||
|
|||||||
@ -14,7 +14,8 @@ import type {
|
|||||||
import type { TabState } from '../../../../global/types';
|
import type { TabState } from '../../../../global/types';
|
||||||
import { ApiMediaFormat } from '../../../../api/types';
|
import { ApiMediaFormat } from '../../../../api/types';
|
||||||
|
|
||||||
import { getPeerTitle, getStickerMediaHash } from '../../../../global/helpers';
|
import { getStickerMediaHash } from '../../../../global/helpers';
|
||||||
|
import { getPeerTitle } from '../../../../global/helpers/peers';
|
||||||
import { selectPeer } from '../../../../global/selectors';
|
import { selectPeer } from '../../../../global/selectors';
|
||||||
import { formatStarsAsIcon } from '../../../../util/localization/format';
|
import { formatStarsAsIcon } from '../../../../util/localization/format';
|
||||||
import { fetch } from '../../../../util/mediaLoader';
|
import { fetch } from '../../../../util/mediaLoader';
|
||||||
|
|||||||
@ -14,8 +14,7 @@ import type { TabState } from '../../../global/types';
|
|||||||
import type { CustomPeer } from '../../../types';
|
import type { CustomPeer } from '../../../types';
|
||||||
|
|
||||||
import { STARS_ICON_PLACEHOLDER } from '../../../config';
|
import { STARS_ICON_PLACEHOLDER } from '../../../config';
|
||||||
import { getPeerTitle } from '../../../global/helpers';
|
import { getPeerTitle, isApiPeerUser } from '../../../global/helpers/peers';
|
||||||
import { isApiPeerUser } from '../../../global/helpers/peers';
|
|
||||||
import {
|
import {
|
||||||
selectChat, selectChatMessage, selectPeer, selectUser,
|
selectChat, selectChatMessage, selectPeer, selectUser,
|
||||||
} from '../../../global/selectors';
|
} from '../../../global/selectors';
|
||||||
|
|||||||
@ -11,8 +11,8 @@ import type { ThreadId } from '../../../types';
|
|||||||
import { MAIN_THREAD_ID } from '../../../api/types';
|
import { MAIN_THREAD_ID } from '../../../api/types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getPeerTitle,
|
|
||||||
} from '../../../global/helpers';
|
} from '../../../global/helpers';
|
||||||
|
import { getPeerTitle } from '../../../global/helpers/peers';
|
||||||
import {
|
import {
|
||||||
selectPeer, selectTabState,
|
selectPeer, selectTabState,
|
||||||
} from '../../../global/selectors';
|
} from '../../../global/selectors';
|
||||||
@ -31,6 +31,8 @@ export type OwnProps = {
|
|||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
isPaymentMessageConfirmDialogOpen: boolean;
|
isPaymentMessageConfirmDialogOpen: boolean;
|
||||||
|
starsBalance: number;
|
||||||
|
isStarsBalanceModalOpen: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SendParams = {
|
export type SendParams = {
|
||||||
@ -39,7 +41,7 @@ export type SendParams = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const SharePreparedMessageModal: FC<OwnProps & StateProps> = ({
|
const SharePreparedMessageModal: FC<OwnProps & StateProps> = ({
|
||||||
modal, isPaymentMessageConfirmDialogOpen,
|
modal, isPaymentMessageConfirmDialogOpen, isStarsBalanceModalOpen, starsBalance,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
closeSharePreparedMessageModal,
|
closeSharePreparedMessageModal,
|
||||||
@ -73,7 +75,7 @@ const SharePreparedMessageModal: FC<OwnProps & StateProps> = ({
|
|||||||
shouldAutoApprove: shouldPaidMessageAutoApprove,
|
shouldAutoApprove: shouldPaidMessageAutoApprove,
|
||||||
setAutoApprove: setShouldPaidMessageAutoApprove,
|
setAutoApprove: setShouldPaidMessageAutoApprove,
|
||||||
handleWithConfirmation: handleActionWithPaymentConfirmation,
|
handleWithConfirmation: handleActionWithPaymentConfirmation,
|
||||||
} = usePaidMessageConfirmation(starsForSendMessage || 0);
|
} = usePaidMessageConfirmation(starsForSendMessage || 0, isStarsBalanceModalOpen, starsBalance);
|
||||||
|
|
||||||
const handleClose = useLastCallback(() => {
|
const handleClose = useLastCallback(() => {
|
||||||
closeSharePreparedMessageModal();
|
closeSharePreparedMessageModal();
|
||||||
@ -118,7 +120,7 @@ const SharePreparedMessageModal: FC<OwnProps & StateProps> = ({
|
|||||||
updateSharePreparedMessageModalSendArgs({ args: { peerId: id, threadId } });
|
updateSharePreparedMessageModalSendArgs({ args: { peerId: id, threadId } });
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleSendWithPaymentConformation = useLastCallback(() => {
|
const handleSendWithPaymentConfirmation = useLastCallback(() => {
|
||||||
if (pendingSendArgs) {
|
if (pendingSendArgs) {
|
||||||
handleActionWithPaymentConfirmation(handleSend, pendingSendArgs.peerId, pendingSendArgs.threadId);
|
handleActionWithPaymentConfirmation(handleSend, pendingSendArgs.peerId, pendingSendArgs.threadId);
|
||||||
}
|
}
|
||||||
@ -131,7 +133,7 @@ const SharePreparedMessageModal: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (pendingSendArgs) {
|
if (pendingSendArgs) {
|
||||||
handleSendWithPaymentConformation();
|
handleSendWithPaymentConfirmation();
|
||||||
}
|
}
|
||||||
}, [pendingSendArgs]);
|
}, [pendingSendArgs]);
|
||||||
|
|
||||||
@ -172,8 +174,12 @@ export default memo(withGlobal(
|
|||||||
(global): StateProps => {
|
(global): StateProps => {
|
||||||
const tabState = selectTabState(global);
|
const tabState = selectTabState(global);
|
||||||
const { isPaymentMessageConfirmDialogOpen } = tabState;
|
const { isPaymentMessageConfirmDialogOpen } = tabState;
|
||||||
|
const starsBalance = global.stars?.balance.amount || 0;
|
||||||
|
const isStarsBalanceModalOpen = Boolean(tabState.starsBalanceModal);
|
||||||
return {
|
return {
|
||||||
isPaymentMessageConfirmDialogOpen,
|
isPaymentMessageConfirmDialogOpen,
|
||||||
|
starsBalance,
|
||||||
|
isStarsBalanceModalOpen,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(SharePreparedMessageModal));
|
)(SharePreparedMessageModal));
|
||||||
|
|||||||
@ -8,7 +8,8 @@ import type { GlobalState, TabState } from '../../../global/types';
|
|||||||
import type { RegularLangKey } from '../../../types/language';
|
import type { RegularLangKey } from '../../../types/language';
|
||||||
|
|
||||||
import { PAID_MESSAGES_PURPOSE } from '../../../config';
|
import { PAID_MESSAGES_PURPOSE } from '../../../config';
|
||||||
import { getChatTitle, getPeerTitle, getUserFullName } from '../../../global/helpers';
|
import { getChatTitle, getUserFullName } from '../../../global/helpers';
|
||||||
|
import { getPeerTitle } from '../../../global/helpers/peers';
|
||||||
import { selectChat, selectIsPremiumPurchaseBlocked, selectUser } from '../../../global/selectors';
|
import { selectChat, selectIsPremiumPurchaseBlocked, selectUser } from '../../../global/selectors';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import renderText from '../../common/helpers/renderText';
|
import renderText from '../../common/helpers/renderText';
|
||||||
|
|||||||
@ -0,0 +1,18 @@
|
|||||||
|
import type { FC } from '../../../../lib/teact/teact';
|
||||||
|
import React from '../../../../lib/teact/teact';
|
||||||
|
|
||||||
|
import type { OwnProps } from './ChatRefundModal';
|
||||||
|
|
||||||
|
import { Bundles } from '../../../../util/moduleLoader';
|
||||||
|
|
||||||
|
import useModuleLoader from '../../../../hooks/useModuleLoader';
|
||||||
|
|
||||||
|
const ChatRefundModalAsync: FC<OwnProps> = (props) => {
|
||||||
|
const { modal } = props;
|
||||||
|
const ChatRefundModal = useModuleLoader(Bundles.Stars, 'ChatRefundModal', !modal);
|
||||||
|
|
||||||
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||||
|
return ChatRefundModal ? <ChatRefundModal {...props} /> : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ChatRefundModalAsync;
|
||||||
84
src/components/modals/stars/chatRefund/ChatRefundModal.tsx
Normal file
84
src/components/modals/stars/chatRefund/ChatRefundModal.tsx
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import React, { memo, useState } from '../../../../lib/teact/teact';
|
||||||
|
import { getActions, withGlobal } from '../../../../global';
|
||||||
|
|
||||||
|
import type { ApiUser } from '../../../../api/types';
|
||||||
|
import type { TabState } from '../../../../global/types';
|
||||||
|
|
||||||
|
import { getPeerTitle } from '../../../../global/helpers/peers';
|
||||||
|
import { selectUser } from '../../../../global/selectors';
|
||||||
|
|
||||||
|
import useCurrentOrPrev from '../../../../hooks/useCurrentOrPrev';
|
||||||
|
import useLang from '../../../../hooks/useLang';
|
||||||
|
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||||
|
|
||||||
|
import Checkbox from '../../../ui/Checkbox';
|
||||||
|
import ConfirmDialog from '../../../ui/ConfirmDialog';
|
||||||
|
|
||||||
|
export type OwnProps = {
|
||||||
|
modal: TabState['chatRefundModal'];
|
||||||
|
};
|
||||||
|
|
||||||
|
type StateProps = {
|
||||||
|
user?: ApiUser;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ChatRefundModal = ({ modal, user }: OwnProps & StateProps) => {
|
||||||
|
const { closeChatRefundModal, addNoPaidMessagesException } = getActions();
|
||||||
|
|
||||||
|
const [shouldRefundStars, setShouldRefundStars] = useState(false);
|
||||||
|
|
||||||
|
const renderingModal = useCurrentOrPrev(modal);
|
||||||
|
const renderingUser = useCurrentOrPrev(user);
|
||||||
|
|
||||||
|
const { starsToRefund, userId } = renderingModal || {};
|
||||||
|
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
|
const isOpen = Boolean(modal);
|
||||||
|
|
||||||
|
const handleConfirmRemoveFee = useLastCallback(() => {
|
||||||
|
closeChatRefundModal();
|
||||||
|
if (!userId) return;
|
||||||
|
addNoPaidMessagesException({ userId, shouldRefundCharged: shouldRefundStars });
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConfirmDialog
|
||||||
|
isOpen={isOpen}
|
||||||
|
onClose={closeChatRefundModal}
|
||||||
|
title={lang('RemoveFeeTitle')}
|
||||||
|
confirmLabel={lang('ConfirmRemoveMessageFee')}
|
||||||
|
confirmHandler={handleConfirmRemoveFee}
|
||||||
|
>
|
||||||
|
{lang('ConfirmDialogMessageRemoveFee', {
|
||||||
|
peer: renderingUser && getPeerTitle(lang, renderingUser),
|
||||||
|
}, {
|
||||||
|
withMarkdown: true,
|
||||||
|
withNodes: true,
|
||||||
|
})}
|
||||||
|
{
|
||||||
|
Boolean(starsToRefund) && (
|
||||||
|
<Checkbox
|
||||||
|
className="dialog-checkbox"
|
||||||
|
label={lang('ConfirmDialogRemoveFeeRefundStars', {
|
||||||
|
amount: starsToRefund,
|
||||||
|
}, {
|
||||||
|
withMarkdown: true,
|
||||||
|
withNodes: true,
|
||||||
|
})}
|
||||||
|
checked={shouldRefundStars}
|
||||||
|
onCheck={setShouldRefundStars}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</ConfirmDialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(withGlobal<OwnProps>((global, { modal }): StateProps => {
|
||||||
|
const user = modal?.userId ? selectUser(global, modal.userId) : undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
user,
|
||||||
|
};
|
||||||
|
})(ChatRefundModal));
|
||||||
@ -3,14 +3,14 @@ import React, {
|
|||||||
memo, useEffect, useMemo, useRef,
|
memo, useEffect, useMemo, useRef,
|
||||||
useState,
|
useState,
|
||||||
} from '../../../../lib/teact/teact';
|
} from '../../../../lib/teact/teact';
|
||||||
import { getActions, getGlobal, withGlobal } from '../../../../global';
|
import { getActions, withGlobal } from '../../../../global';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ApiStarTopupOption, ApiUser,
|
ApiStarTopupOption, ApiUser,
|
||||||
} from '../../../../api/types';
|
} from '../../../../api/types';
|
||||||
import type { TabState } from '../../../../global/types';
|
import type { TabState } from '../../../../global/types';
|
||||||
|
|
||||||
import { getPeerTitle } from '../../../../global/helpers';
|
import { getPeerTitle } from '../../../../global/helpers/peers';
|
||||||
import {
|
import {
|
||||||
selectUser,
|
selectUser,
|
||||||
} from '../../../../global/selectors';
|
} from '../../../../global/selectors';
|
||||||
@ -213,7 +213,7 @@ const StarsGiftModal: FC<OwnProps & StateProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default memo(withGlobal<OwnProps>((global, { modal }): StateProps => {
|
export default memo(withGlobal<OwnProps>((global, { modal }): StateProps => {
|
||||||
const user = modal?.forUserId ? selectUser(getGlobal(), modal.forUserId) : undefined;
|
const user = modal?.forUserId ? selectUser(global, modal.forUserId) : undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
user,
|
user,
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import type {
|
|||||||
} from '../../../../api/types';
|
} from '../../../../api/types';
|
||||||
import type { GlobalState } from '../../../../global/types';
|
import type { GlobalState } from '../../../../global/types';
|
||||||
|
|
||||||
import { getPeerTitle } from '../../../../global/helpers';
|
import { getPeerTitle } from '../../../../global/helpers/peers';
|
||||||
import { selectPeer } from '../../../../global/selectors';
|
import { selectPeer } from '../../../../global/selectors';
|
||||||
import { formatDateToString } from '../../../../util/dates/dateFormat';
|
import { formatDateToString } from '../../../../util/dates/dateFormat';
|
||||||
import { formatInteger } from '../../../../util/textFormat';
|
import { formatInteger } from '../../../../util/textFormat';
|
||||||
|
|||||||
@ -8,8 +8,8 @@ import type {
|
|||||||
import type { GlobalState } from '../../../../global/types';
|
import type { GlobalState } from '../../../../global/types';
|
||||||
import type { CustomPeer } from '../../../../types';
|
import type { CustomPeer } from '../../../../types';
|
||||||
|
|
||||||
import { getPeerTitle } from '../../../../global/helpers';
|
|
||||||
import { buildStarsTransactionCustomPeer, formatStarsTransactionAmount } from '../../../../global/helpers/payments';
|
import { buildStarsTransactionCustomPeer, formatStarsTransactionAmount } from '../../../../global/helpers/payments';
|
||||||
|
import { getPeerTitle } from '../../../../global/helpers/peers';
|
||||||
import { selectPeer } from '../../../../global/selectors';
|
import { selectPeer } from '../../../../global/selectors';
|
||||||
import buildClassName from '../../../../util/buildClassName';
|
import buildClassName from '../../../../util/buildClassName';
|
||||||
import { formatDateTimeToString } from '../../../../util/dates/dateFormat';
|
import { formatDateTimeToString } from '../../../../util/dates/dateFormat';
|
||||||
|
|||||||
@ -15,7 +15,8 @@ import type { Signal } from '../../util/signals';
|
|||||||
import { MAIN_THREAD_ID } from '../../api/types';
|
import { MAIN_THREAD_ID } from '../../api/types';
|
||||||
|
|
||||||
import { EDITABLE_STORY_INPUT_CSS_SELECTOR, EDITABLE_STORY_INPUT_ID } from '../../config';
|
import { EDITABLE_STORY_INPUT_CSS_SELECTOR, EDITABLE_STORY_INPUT_ID } from '../../config';
|
||||||
import { getPeerTitle, isChatChannel, isUserId } from '../../global/helpers';
|
import { isChatChannel, isUserId } from '../../global/helpers';
|
||||||
|
import { getPeerTitle } from '../../global/helpers/peers';
|
||||||
import {
|
import {
|
||||||
selectChat,
|
selectChat,
|
||||||
selectIsCurrentUserPremium,
|
selectIsCurrentUserPremium,
|
||||||
|
|||||||
@ -6,7 +6,8 @@ import type {
|
|||||||
} from '../../api/types';
|
} from '../../api/types';
|
||||||
import type { StoryViewerOrigin } from '../../types';
|
import type { StoryViewerOrigin } from '../../types';
|
||||||
|
|
||||||
import { getPeerTitle, getStoryMediaHash } from '../../global/helpers';
|
import { getStoryMediaHash } from '../../global/helpers';
|
||||||
|
import { getPeerTitle } from '../../global/helpers/peers';
|
||||||
import { selectTabState } from '../../global/selectors';
|
import { selectTabState } from '../../global/selectors';
|
||||||
import renderText from '../common/helpers/renderText';
|
import renderText from '../common/helpers/renderText';
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,8 @@ import { getActions } from '../../global';
|
|||||||
import type { ApiPeer } from '../../api/types';
|
import type { ApiPeer } from '../../api/types';
|
||||||
import { StoryViewerOrigin } from '../../types';
|
import { StoryViewerOrigin } from '../../types';
|
||||||
|
|
||||||
import { getPeerTitle, isUserId } from '../../global/helpers';
|
import { isUserId } from '../../global/helpers';
|
||||||
|
import { getPeerTitle } from '../../global/helpers/peers';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { preventMessageInputBlurWithBubbling } from '../middle/helpers/preventMessageInputBlur';
|
import { preventMessageInputBlurWithBubbling } from '../middle/helpers/preventMessageInputBlur';
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,8 @@ import type {
|
|||||||
} from '../../api/types';
|
} from '../../api/types';
|
||||||
import type { IconName } from '../../types/icons';
|
import type { IconName } from '../../types/icons';
|
||||||
|
|
||||||
import { getPeerTitle, getUserFullName } from '../../global/helpers';
|
import { getUserFullName } from '../../global/helpers';
|
||||||
|
import { getPeerTitle } from '../../global/helpers/peers';
|
||||||
import { selectPeerStory, selectTabState } from '../../global/selectors';
|
import { selectPeerStory, selectTabState } from '../../global/selectors';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { getHours } from '../../util/dates/units';
|
import { getHours } from '../../util/dates/units';
|
||||||
|
|||||||
@ -11,6 +11,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.Notification {
|
.Notification {
|
||||||
|
--color-toast-action: var(--color-primary);
|
||||||
|
|
||||||
background-color: rgba(32, 32, 32, 0.8);
|
background-color: rgba(32, 32, 32, 0.8);
|
||||||
background-size: 1.5rem;
|
background-size: 1.5rem;
|
||||||
border-radius: var(--border-radius-default);
|
border-radius: var(--border-radius-default);
|
||||||
|
|||||||
@ -54,6 +54,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.canCheckedInDisabled {
|
||||||
|
.Radio-main {
|
||||||
|
&::before {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
> input {
|
> input {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: var(--z-below);
|
z-index: var(--z-below);
|
||||||
|
|||||||
@ -18,6 +18,7 @@ type OwnProps = {
|
|||||||
value?: string;
|
value?: string;
|
||||||
checked?: boolean;
|
checked?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
isCanCheckedInDisabled?: boolean;
|
||||||
isLink?: boolean;
|
isLink?: boolean;
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
@ -46,6 +47,7 @@ const Radio: FC<OwnProps> = ({
|
|||||||
isLink,
|
isLink,
|
||||||
onChange,
|
onChange,
|
||||||
onSubLabelClick,
|
onSubLabelClick,
|
||||||
|
isCanCheckedInDisabled,
|
||||||
}) => {
|
}) => {
|
||||||
const lang = useOldLang();
|
const lang = useOldLang();
|
||||||
|
|
||||||
@ -58,6 +60,7 @@ const Radio: FC<OwnProps> = ({
|
|||||||
isLoading && 'loading',
|
isLoading && 'loading',
|
||||||
onlyInput && 'onlyInput',
|
onlyInput && 'onlyInput',
|
||||||
Boolean(subLabel) && 'withSubLabel',
|
Boolean(subLabel) && 'withSubLabel',
|
||||||
|
isCanCheckedInDisabled && 'canCheckedInDisabled',
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -14,6 +14,7 @@ export type IRadioOption<T = string> = {
|
|||||||
value: T;
|
value: T;
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
isCanCheckedInDisabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
@ -67,6 +68,7 @@ const RadioGroup: FC<OwnProps> = ({
|
|||||||
value={option.value}
|
value={option.value}
|
||||||
checked={option.value === selected}
|
checked={option.value === selected}
|
||||||
hidden={option.hidden}
|
hidden={option.hidden}
|
||||||
|
isCanCheckedInDisabled={option.isCanCheckedInDisabled}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
withIcon={withIcon}
|
withIcon={withIcon}
|
||||||
isLoading={loadingOption ? loadingOption === option.value : undefined}
|
isLoading={loadingOption ? loadingOption === option.value : undefined}
|
||||||
|
|||||||
@ -416,7 +416,7 @@ addActionHandler('sendInlineBotResult', async (global, actions, payload): Promis
|
|||||||
actions.resetDraftReplyInfo({ tabId });
|
actions.resetDraftReplyInfo({ tabId });
|
||||||
actions.clearWebPagePreview({ tabId });
|
actions.clearWebPagePreview({ tabId });
|
||||||
|
|
||||||
const starsForOneMessage = await getPeerStarsForMessage(global, chat);
|
const starsForOneMessage = await getPeerStarsForMessage(global, chatId);
|
||||||
const params = {
|
const params = {
|
||||||
chat,
|
chat,
|
||||||
id,
|
id,
|
||||||
|
|||||||
@ -8,7 +8,6 @@ import type {
|
|||||||
ApiInputStoryReplyInfo,
|
ApiInputStoryReplyInfo,
|
||||||
ApiMessage,
|
ApiMessage,
|
||||||
ApiOnProgress,
|
ApiOnProgress,
|
||||||
ApiPeer,
|
|
||||||
ApiStory,
|
ApiStory,
|
||||||
ApiUser,
|
ApiUser,
|
||||||
} from '../../../api/types';
|
} from '../../../api/types';
|
||||||
@ -61,12 +60,11 @@ import {
|
|||||||
isChatSuperGroup,
|
isChatSuperGroup,
|
||||||
isDeletedUser,
|
isDeletedUser,
|
||||||
isMessageLocal,
|
isMessageLocal,
|
||||||
isPeerUser,
|
|
||||||
isServiceNotificationMessage,
|
isServiceNotificationMessage,
|
||||||
isUserBot,
|
isUserBot,
|
||||||
splitMessagesForForwarding,
|
splitMessagesForForwarding,
|
||||||
} from '../../helpers';
|
} from '../../helpers';
|
||||||
import { isApiPeerUser } from '../../helpers/peers';
|
import { isApiPeerChat, isApiPeerUser } from '../../helpers/peers';
|
||||||
import {
|
import {
|
||||||
addActionHandler, getActions, getGlobal, setGlobal,
|
addActionHandler, getActions, getGlobal, setGlobal,
|
||||||
} from '../../index';
|
} from '../../index';
|
||||||
@ -345,7 +343,7 @@ addActionHandler('sendMessage', async (global, actions, payload): Promise<void>
|
|||||||
|
|
||||||
const replyInfo = storyReplyInfo || messageReplyInfo;
|
const replyInfo = storyReplyInfo || messageReplyInfo;
|
||||||
const lastMessageId = selectChatLastMessageId(global, chatId!);
|
const lastMessageId = selectChatLastMessageId(global, chatId!);
|
||||||
const messagePriceInStars = await getPeerStarsForMessage(global, chat);
|
const messagePriceInStars = await getPeerStarsForMessage(global, chatId!);
|
||||||
|
|
||||||
const params : SendMessageParams = {
|
const params : SendMessageParams = {
|
||||||
...payload,
|
...payload,
|
||||||
@ -1607,9 +1605,12 @@ function getViewportSlice(
|
|||||||
|
|
||||||
export async function getPeerStarsForMessage<T extends GlobalState>(
|
export async function getPeerStarsForMessage<T extends GlobalState>(
|
||||||
global: T,
|
global: T,
|
||||||
peer: ApiPeer,
|
peerId: string,
|
||||||
): Promise<number | undefined> {
|
): Promise<number | undefined> {
|
||||||
if (!isPeerUser(peer)) {
|
const peer = selectPeer(global, peerId);
|
||||||
|
if (!peer) return undefined;
|
||||||
|
|
||||||
|
if (isApiPeerChat(peer)) {
|
||||||
return peer.paidMessagesStars;
|
return peer.paidMessagesStars;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1617,7 +1618,7 @@ export async function getPeerStarsForMessage<T extends GlobalState>(
|
|||||||
|
|
||||||
const fullInfo = selectUserFullInfo(global, peer.id);
|
const fullInfo = selectUserFullInfo(global, peer.id);
|
||||||
if (fullInfo) {
|
if (fullInfo) {
|
||||||
return fullInfo?.paidMessagesStars;
|
return fullInfo.paidMessagesStars;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await callApi('fetchPaidMessagesStarsAmount', peer);
|
const result = await callApi('fetchPaidMessagesStarsAmount', peer);
|
||||||
@ -1675,7 +1676,7 @@ async function sendMessagesWithNotification<T extends GlobalState>(
|
|||||||
) {
|
) {
|
||||||
const chat = sendParams[0]?.chat;
|
const chat = sendParams[0]?.chat;
|
||||||
if (!chat || !sendParams.length) return;
|
if (!chat || !sendParams.length) return;
|
||||||
const starsForOneMessage = await getPeerStarsForMessage(global, chat);
|
const starsForOneMessage = await getPeerStarsForMessage(global, chat.id);
|
||||||
if (!starsForOneMessage) {
|
if (!starsForOneMessage) {
|
||||||
// eslint-disable-next-line eslint-multitab-tt/no-getactions-in-actions
|
// eslint-disable-next-line eslint-multitab-tt/no-getactions-in-actions
|
||||||
getActions().sendMessages({ sendParams });
|
getActions().sendMessages({ sendParams });
|
||||||
|
|||||||
@ -204,6 +204,27 @@ addActionHandler('addNoPaidMessagesException', async (global, actions, payload):
|
|||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addActionHandler('openChatRefundModal', async (global, actions, payload): Promise<void> => {
|
||||||
|
const { userId, tabId = getCurrentTabId() } = payload;
|
||||||
|
const user = selectUser(global, userId);
|
||||||
|
if (!user) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const starsAmount = await callApi('fetchPaidMessagesRevenue', { user });
|
||||||
|
if (starsAmount === undefined) return;
|
||||||
|
|
||||||
|
global = getGlobal();
|
||||||
|
global = updateTabState(global, {
|
||||||
|
chatRefundModal: {
|
||||||
|
userId,
|
||||||
|
starsToRefund: starsAmount,
|
||||||
|
},
|
||||||
|
}, tabId);
|
||||||
|
|
||||||
|
setGlobal(global);
|
||||||
|
});
|
||||||
|
|
||||||
addActionHandler('updateContact', async (global, actions, payload): Promise<void> => {
|
addActionHandler('updateContact', async (global, actions, payload): Promise<void> => {
|
||||||
const {
|
const {
|
||||||
userId, isMuted = false, firstName, lastName, shouldSharePhoneNumber,
|
userId, isMuted = false, firstName, lastName, shouldSharePhoneNumber,
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { PaymentStep } from '../../../types';
|
|||||||
|
|
||||||
import { SERVICE_NOTIFICATIONS_USER_ID } from '../../../config';
|
import { SERVICE_NOTIFICATIONS_USER_ID } from '../../../config';
|
||||||
import { applyLangPackDifference, getTranslationFn, requestLangPackDifference } from '../../../util/localization';
|
import { applyLangPackDifference, getTranslationFn, requestLangPackDifference } from '../../../util/localization';
|
||||||
import { getPeerTitle } from '../../helpers';
|
import { getPeerTitle } from '../../helpers/peers';
|
||||||
import { addActionHandler, setGlobal } from '../../index';
|
import { addActionHandler, setGlobal } from '../../index';
|
||||||
import {
|
import {
|
||||||
addBlockedUser,
|
addBlockedUser,
|
||||||
|
|||||||
@ -40,7 +40,6 @@ addActionHandler('processOpenChatOrThread', (global, actions, payload): ActionRe
|
|||||||
|
|
||||||
actions.closeStoryViewer({ tabId });
|
actions.closeStoryViewer({ tabId });
|
||||||
actions.closeStarsBalanceModal({ tabId });
|
actions.closeStarsBalanceModal({ tabId });
|
||||||
actions.closeStarsBalanceModal({ tabId });
|
|
||||||
actions.closeStarsTransactionModal({ tabId });
|
actions.closeStarsTransactionModal({ tabId });
|
||||||
|
|
||||||
if (!currentMessageList || (
|
if (!currentMessageList || (
|
||||||
|
|||||||
@ -29,10 +29,10 @@ import {
|
|||||||
getMediaHash,
|
getMediaHash,
|
||||||
getMessageDownloadableMedia,
|
getMessageDownloadableMedia,
|
||||||
getMessageStatefulContent,
|
getMessageStatefulContent,
|
||||||
getPeerTitle,
|
|
||||||
isChatChannel,
|
isChatChannel,
|
||||||
} from '../../helpers';
|
} from '../../helpers';
|
||||||
import { getMessageSummaryText } from '../../helpers/messageSummary';
|
import { getMessageSummaryText } from '../../helpers/messageSummary';
|
||||||
|
import { getPeerTitle } from '../../helpers/peers';
|
||||||
import { renderMessageSummaryHtml } from '../../helpers/renderMessageSummaryHtml';
|
import { renderMessageSummaryHtml } from '../../helpers/renderMessageSummaryHtml';
|
||||||
import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
||||||
import {
|
import {
|
||||||
@ -62,7 +62,6 @@ import {
|
|||||||
selectIsRightColumnShown,
|
selectIsRightColumnShown,
|
||||||
selectIsViewportNewest,
|
selectIsViewportNewest,
|
||||||
selectMessageIdsByGroupId,
|
selectMessageIdsByGroupId,
|
||||||
selectPeer,
|
|
||||||
selectPinnedIds,
|
selectPinnedIds,
|
||||||
selectReplyStack,
|
selectReplyStack,
|
||||||
selectRequestedChatTranslationLanguage,
|
selectRequestedChatTranslationLanguage,
|
||||||
@ -1115,8 +1114,7 @@ addActionHandler('updateSharePreparedMessageModalSendArgs', async (global, actio
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const peer = selectPeer(global, args.peerId);
|
const starsForSendMessage = await getPeerStarsForMessage(global, args.peerId);
|
||||||
const starsForSendMessage = peer ? await getPeerStarsForMessage(global, peer) : undefined;
|
|
||||||
|
|
||||||
global = getGlobal();
|
global = getGlobal();
|
||||||
global = updateTabState(global, {
|
global = updateTabState(global, {
|
||||||
|
|||||||
@ -32,6 +32,7 @@ import {
|
|||||||
selectCurrentMessageList,
|
selectCurrentMessageList,
|
||||||
selectIsCurrentUserPremium,
|
selectIsCurrentUserPremium,
|
||||||
selectIsTrustedBot,
|
selectIsTrustedBot,
|
||||||
|
selectPeerPaidMessagesStars,
|
||||||
selectSender,
|
selectSender,
|
||||||
selectTabState,
|
selectTabState,
|
||||||
selectTopic,
|
selectTopic,
|
||||||
@ -325,7 +326,19 @@ addActionHandler('showNotification', (global, actions, payload): ActionReturnTyp
|
|||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('showAllowedMessageTypesNotification', (global, actions, payload): ActionReturnType => {
|
addActionHandler('showAllowedMessageTypesNotification', (global, actions, payload): ActionReturnType => {
|
||||||
const { chatId, tabId = getCurrentTabId() } = payload;
|
const { chatId, messageListType, tabId = getCurrentTabId() } = payload;
|
||||||
|
|
||||||
|
const paidMessagesStars = selectPeerPaidMessagesStars(global, chatId);
|
||||||
|
|
||||||
|
if (paidMessagesStars && messageListType === 'scheduled') {
|
||||||
|
actions.showNotification({
|
||||||
|
message: {
|
||||||
|
key: 'DescriptionScheduledPaidMessagesNotAllowed',
|
||||||
|
},
|
||||||
|
tabId,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const chat = selectChat(global, chatId);
|
const chat = selectChat(global, chatId);
|
||||||
if (!chat) return;
|
if (!chat) return;
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
|||||||
import { addStoriesForPeer } from '../../reducers';
|
import { addStoriesForPeer } from '../../reducers';
|
||||||
import { updateTabState } from '../../reducers/tabs';
|
import { updateTabState } from '../../reducers/tabs';
|
||||||
import {
|
import {
|
||||||
selectChat,
|
|
||||||
selectCurrentViewedStory,
|
selectCurrentViewedStory,
|
||||||
selectPeer,
|
selectPeer,
|
||||||
selectPeerFirstStoryId,
|
selectPeerFirstStoryId,
|
||||||
@ -296,13 +295,11 @@ addActionHandler('sendMessage', async (global, actions, payload): Promise<void>
|
|||||||
const { storyId, peerId: storyPeerId } = selectCurrentViewedStory(global, tabId);
|
const { storyId, peerId: storyPeerId } = selectCurrentViewedStory(global, tabId);
|
||||||
const isStoryReply = Boolean(storyId && storyPeerId);
|
const isStoryReply = Boolean(storyId && storyPeerId);
|
||||||
|
|
||||||
const chat = storyPeerId ? selectChat(global, storyPeerId) : undefined;
|
if (!isStoryReply) {
|
||||||
if (!chat) return;
|
|
||||||
const messagePriceInStars = await getPeerStarsForMessage(global, chat);
|
|
||||||
|
|
||||||
if (!isStoryReply || messagePriceInStars) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const messagePriceInStars = await getPeerStarsForMessage(global, storyPeerId!);
|
||||||
|
if (messagePriceInStars === undefined) return;
|
||||||
|
|
||||||
const { gif, sticker, isReaction } = payload;
|
const { gif, sticker, isReaction } = payload;
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import type { ActionReturnType } from '../../types';
|
import type { ActionReturnType } from '../../types';
|
||||||
|
|
||||||
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
||||||
|
import { addTabStateResetterAction } from '../../helpers/meta';
|
||||||
import { addActionHandler } from '../../index';
|
import { addActionHandler } from '../../index';
|
||||||
import { closeNewContactDialog, updateUserSearch } from '../../reducers';
|
import { closeNewContactDialog, updateUserSearch } from '../../reducers';
|
||||||
import { updateTabState } from '../../reducers/tabs';
|
import { updateTabState } from '../../reducers/tabs';
|
||||||
@ -50,3 +51,5 @@ addActionHandler('closeSuggestedStatusModal', (global, actions, payload): Action
|
|||||||
suggestedStatusModal: undefined,
|
suggestedStatusModal: undefined,
|
||||||
}, tabId);
|
}, tabId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addTabStateResetterAction('closeChatRefundModal', 'chatRefundModal');
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import type {
|
|||||||
ApiPeer,
|
ApiPeer,
|
||||||
ApiPreparedInlineMessage,
|
ApiPreparedInlineMessage,
|
||||||
ApiTopic,
|
ApiTopic,
|
||||||
ApiUser,
|
|
||||||
} from '../../api/types';
|
} from '../../api/types';
|
||||||
import type { OldLangFn } from '../../hooks/useOldLang';
|
import type { OldLangFn } from '../../hooks/useOldLang';
|
||||||
import type {
|
import type {
|
||||||
@ -27,7 +26,7 @@ import { formatDateToString, formatTime } from '../../util/dates/dateFormat';
|
|||||||
import { getServerTime } from '../../util/serverTime';
|
import { getServerTime } from '../../util/serverTime';
|
||||||
import { getGlobal } from '..';
|
import { getGlobal } from '..';
|
||||||
import { isSystemBot } from './bots';
|
import { isSystemBot } from './bots';
|
||||||
import { getMainUsername, getUserFirstOrLastName } from './users';
|
import { getMainUsername } from './users';
|
||||||
|
|
||||||
const FOREVER_BANNED_DATE = Date.now() / 1000 + 31622400; // 366 days
|
const FOREVER_BANNED_DATE = Date.now() / 1000 + 31622400; // 366 days
|
||||||
|
|
||||||
@ -35,14 +34,6 @@ export function isUserId(entityId: string) {
|
|||||||
return !entityId.startsWith('-');
|
return !entityId.startsWith('-');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isPeerChat(entity: ApiPeer): entity is ApiChat {
|
|
||||||
return 'title' in entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isPeerUser(entity: ApiPeer): entity is ApiUser {
|
|
||||||
return !isPeerChat(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isChannelId(entityId: string) {
|
export function isChannelId(entityId: string) {
|
||||||
return entityId.length === CHANNEL_ID_LENGTH && entityId.startsWith('-1');
|
return entityId.length === CHANNEL_ID_LENGTH && entityId.startsWith('-1');
|
||||||
}
|
}
|
||||||
@ -211,8 +202,10 @@ export function getAllowedAttachmentOptions(
|
|||||||
chatFullInfo?: ApiChatFullInfo,
|
chatFullInfo?: ApiChatFullInfo,
|
||||||
isChatWithBot = false,
|
isChatWithBot = false,
|
||||||
isStoryReply = false,
|
isStoryReply = false,
|
||||||
|
paidMessagesStars?: number,
|
||||||
|
isInScheduledList = false,
|
||||||
): IAllowedAttachmentOptions {
|
): IAllowedAttachmentOptions {
|
||||||
if (!chat) {
|
if (!chat || (paidMessagesStars && isInScheduledList)) {
|
||||||
return {
|
return {
|
||||||
canAttachMedia: false,
|
canAttachMedia: false,
|
||||||
canAttachPolls: false,
|
canAttachPolls: false,
|
||||||
@ -345,24 +338,6 @@ export function getFolderDescriptionText(lang: OldLangFn, folder: ApiChatFolder,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMessageSenderName(lang: OldLangFn, chatId: string, sender?: ApiPeer) {
|
|
||||||
if (!sender || isUserId(chatId)) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPeerChat(sender)) {
|
|
||||||
if (chatId === sender.id) return undefined;
|
|
||||||
|
|
||||||
return sender.title;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sender.isSelf) {
|
|
||||||
return lang('FromYou');
|
|
||||||
}
|
|
||||||
|
|
||||||
return getUserFirstOrLastName(sender);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isChatPublic(chat: ApiChat) {
|
export function isChatPublic(chat: ApiChat) {
|
||||||
return chat.usernames?.some(({ isActive }) => isActive);
|
return chat.usernames?.some(({ isActive }) => isActive);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,9 +9,7 @@ import type {
|
|||||||
import type {
|
import type {
|
||||||
ApiPoll, MediaContainer, StatefulMediaContent,
|
ApiPoll, MediaContainer, StatefulMediaContent,
|
||||||
} from '../../api/types/messages';
|
} from '../../api/types/messages';
|
||||||
import type { OldLangFn } from '../../hooks/useOldLang';
|
import type { ThreadId } from '../../types';
|
||||||
import type { CustomPeer, ThreadId } from '../../types';
|
|
||||||
import type { LangFn } from '../../util/localization';
|
|
||||||
import type { GlobalState } from '../types';
|
import type { GlobalState } from '../types';
|
||||||
import { ApiMessageEntityTypes, MAIN_THREAD_ID } from '../../api/types';
|
import { ApiMessageEntityTypes, MAIN_THREAD_ID } from '../../api/types';
|
||||||
|
|
||||||
@ -32,9 +30,9 @@ import { isLocalMessageId } from '../../util/keys/messageKey';
|
|||||||
import { getServerTime } from '../../util/serverTime';
|
import { getServerTime } from '../../util/serverTime';
|
||||||
import { getGlobal } from '../index';
|
import { getGlobal } from '../index';
|
||||||
import {
|
import {
|
||||||
getChatTitle, getCleanPeerId, isPeerUser, isUserId,
|
getCleanPeerId, isUserId,
|
||||||
} from './chats';
|
} from './chats';
|
||||||
import { getMainUsername, getUserFirstOrLastName, getUserFullName } from './users';
|
import { getMainUsername } from './users';
|
||||||
|
|
||||||
const RE_LINK = new RegExp(RE_LINK_TEMPLATE, 'i');
|
const RE_LINK = new RegExp(RE_LINK_TEMPLATE, 'i');
|
||||||
|
|
||||||
@ -209,24 +207,6 @@ export function isAnonymousOwnMessage(message: ApiMessage) {
|
|||||||
return Boolean(message.senderId) && !isUserId(message.senderId) && isOwnMessage(message);
|
return Boolean(message.senderId) && !isUserId(message.senderId) && isOwnMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPeerTitle(lang: OldLangFn | LangFn, peer: ApiPeer | CustomPeer) {
|
|
||||||
if (!peer) return undefined;
|
|
||||||
if ('isCustomPeer' in peer) {
|
|
||||||
// TODO: Remove any after full migration to new lang
|
|
||||||
return peer.titleKey ? lang(peer.titleKey as any) : peer.title;
|
|
||||||
}
|
|
||||||
return isPeerUser(peer) ? getUserFirstOrLastName(peer) : getChatTitle(lang, peer);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getPeerFullTitle(lang: OldLangFn | LangFn, peer: ApiPeer | CustomPeer) {
|
|
||||||
if (!peer) return undefined;
|
|
||||||
if ('isCustomPeer' in peer) {
|
|
||||||
// TODO: Remove any after full migration to new lang
|
|
||||||
return peer.titleKey ? lang(peer.titleKey as any) : peer.title;
|
|
||||||
}
|
|
||||||
return isPeerUser(peer) ? getUserFullName(peer) : getChatTitle(lang, peer);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getSendingState(message: ApiMessage) {
|
export function getSendingState(message: ApiMessage) {
|
||||||
if (!message.sendingState) {
|
if (!message.sendingState) {
|
||||||
return 'succeeded';
|
return 'succeeded';
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
import type { ApiChat, ApiPeer, ApiUser } from '../../api/types';
|
import type { ApiChat, ApiPeer, ApiUser } from '../../api/types';
|
||||||
|
import type { OldLangFn } from '../../hooks/useOldLang';
|
||||||
|
import type { CustomPeer } from '../../types';
|
||||||
|
|
||||||
import { SERVICE_NOTIFICATIONS_USER_ID } from '../../config';
|
import { SERVICE_NOTIFICATIONS_USER_ID } from '../../config';
|
||||||
import { getTranslationFn } from '../../util/localization';
|
import { getTranslationFn, type LangFn } from '../../util/localization';
|
||||||
import { prepareSearchWordsForNeedle } from '../../util/searchWords';
|
import { prepareSearchWordsForNeedle } from '../../util/searchWords';
|
||||||
import { selectChat, selectPeer, selectUser } from '../selectors';
|
import { selectChat, selectPeer, selectUser } from '../selectors';
|
||||||
import { getGlobal } from '..';
|
import { getGlobal } from '..';
|
||||||
import { getChatTitle } from './chats';
|
import { getChatTitle, isUserId } from './chats';
|
||||||
import { getPeerFullTitle } from './messages';
|
import { getUserFirstOrLastName, getUserFullName } from './users';
|
||||||
|
|
||||||
export function isApiPeerChat(peer: ApiPeer): peer is ApiChat {
|
export function isApiPeerChat(peer: ApiPeer): peer is ApiChat {
|
||||||
return 'title' in peer;
|
return 'title' in peer;
|
||||||
@ -89,3 +91,39 @@ export function getPeerTypeKey(peer: ApiPeer) {
|
|||||||
|
|
||||||
return 'ChatList.PeerTypeNonContactUser';
|
return 'ChatList.PeerTypeNonContactUser';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getPeerTitle(lang: OldLangFn | LangFn, peer: ApiPeer | CustomPeer) {
|
||||||
|
if (!peer) return undefined;
|
||||||
|
if ('isCustomPeer' in peer) {
|
||||||
|
// TODO: Remove any after full migration to new lang
|
||||||
|
return peer.titleKey ? lang(peer.titleKey as any) : peer.title;
|
||||||
|
}
|
||||||
|
return isApiPeerUser(peer) ? getUserFirstOrLastName(peer) : getChatTitle(lang, peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPeerFullTitle(lang: OldLangFn | LangFn, peer: ApiPeer | CustomPeer) {
|
||||||
|
if (!peer) return undefined;
|
||||||
|
if ('isCustomPeer' in peer) {
|
||||||
|
// TODO: Remove any after full migration to new lang
|
||||||
|
return peer.titleKey ? lang(peer.titleKey as any) : peer.title;
|
||||||
|
}
|
||||||
|
return isApiPeerUser(peer) ? getUserFullName(peer) : getChatTitle(lang, peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMessageSenderName(lang: OldLangFn, chatId: string, sender?: ApiPeer) {
|
||||||
|
if (!sender || isUserId(chatId)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isApiPeerChat(sender)) {
|
||||||
|
if (chatId === sender.id) return undefined;
|
||||||
|
|
||||||
|
return sender.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sender.isSelf) {
|
||||||
|
return lang('FromYou');
|
||||||
|
}
|
||||||
|
|
||||||
|
return getUserFirstOrLastName(sender);
|
||||||
|
}
|
||||||
|
|||||||
@ -1741,6 +1741,10 @@ export interface ActionPayloads {
|
|||||||
userId: string;
|
userId: string;
|
||||||
shouldRefundCharged: boolean;
|
shouldRefundCharged: boolean;
|
||||||
};
|
};
|
||||||
|
openChatRefundModal: {
|
||||||
|
userId: string;
|
||||||
|
} & WithTabId;
|
||||||
|
closeChatRefundModal: WithTabId | undefined;
|
||||||
loadMoreProfilePhotos: {
|
loadMoreProfilePhotos: {
|
||||||
peerId: string;
|
peerId: string;
|
||||||
isPreload?: boolean;
|
isPreload?: boolean;
|
||||||
@ -2186,6 +2190,7 @@ export interface ActionPayloads {
|
|||||||
showNotification: Omit<ApiNotification, 'localId'> & { localId?: string } & WithTabId;
|
showNotification: Omit<ApiNotification, 'localId'> & { localId?: string } & WithTabId;
|
||||||
showAllowedMessageTypesNotification: {
|
showAllowedMessageTypesNotification: {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
|
messageListType?: MessageListType;
|
||||||
} & WithTabId;
|
} & WithTabId;
|
||||||
dismissNotification: { localId: string } & WithTabId;
|
dismissNotification: { localId: string } & WithTabId;
|
||||||
|
|
||||||
|
|||||||
@ -638,6 +638,10 @@ export type TabState = {
|
|||||||
forPeerId: string;
|
forPeerId: string;
|
||||||
gifts?: ApiPremiumGiftCodeOption[];
|
gifts?: ApiPremiumGiftCodeOption[];
|
||||||
};
|
};
|
||||||
|
chatRefundModal?: {
|
||||||
|
userId: string;
|
||||||
|
starsToRefund: number;
|
||||||
|
};
|
||||||
|
|
||||||
limitReachedModal?: {
|
limitReachedModal?: {
|
||||||
limit: ApiLimitTypeWithModal;
|
limit: ApiLimitTypeWithModal;
|
||||||
|
|||||||
@ -6,8 +6,9 @@ import type {
|
|||||||
} from '../api/types';
|
} from '../api/types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getAudioHasCover, getChatAvatarHash, getChatTitle, getMediaHash, getMessageContent, getPeerTitle,
|
getAudioHasCover, getChatAvatarHash, getChatTitle, getMediaHash, getMessageContent,
|
||||||
} from '../global/helpers';
|
} from '../global/helpers';
|
||||||
|
import { getPeerTitle } from '../global/helpers/peers';
|
||||||
import { resizeImage, scaleImage } from '../util/imageResize';
|
import { resizeImage, scaleImage } from '../util/imageResize';
|
||||||
import { buildMediaMetadata } from '../util/mediaSession';
|
import { buildMediaMetadata } from '../util/mediaSession';
|
||||||
import { AVATAR_FULL_DIMENSIONS } from '../components/common/helpers/mediaDimensions';
|
import { AVATAR_FULL_DIMENSIONS } from '../components/common/helpers/mediaDimensions';
|
||||||
|
|||||||
@ -1473,6 +1473,7 @@ account.resolveBusinessChatLink#5492e5ee slug:string = account.ResolvedBusinessC
|
|||||||
account.toggleSponsoredMessages#b9d9a38d enabled:Bool = Bool;
|
account.toggleSponsoredMessages#b9d9a38d enabled:Bool = Bool;
|
||||||
account.getCollectibleEmojiStatuses#2e7b4543 hash:long = account.EmojiStatuses;
|
account.getCollectibleEmojiStatuses#2e7b4543 hash:long = account.EmojiStatuses;
|
||||||
account.addNoPaidMessagesException#6f688aa7 flags:# refund_charged:flags.0?true user_id:InputUser = Bool;
|
account.addNoPaidMessagesException#6f688aa7 flags:# refund_charged:flags.0?true user_id:InputUser = Bool;
|
||||||
|
account.getPaidMessagesRevenue#f1266f38 user_id:InputUser = account.PaidMessagesRevenue;
|
||||||
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
|
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
|
||||||
users.getFullUser#b60f5918 id:InputUser = users.UserFull;
|
users.getFullUser#b60f5918 id:InputUser = users.UserFull;
|
||||||
users.getRequirementsToContact#d89a83a3 id:Vector<InputUser> = Vector<RequirementToContact>;
|
users.getRequirementsToContact#d89a83a3 id:Vector<InputUser> = Vector<RequirementToContact>;
|
||||||
|
|||||||
@ -62,6 +62,7 @@
|
|||||||
"account.toggleSponsoredMessages",
|
"account.toggleSponsoredMessages",
|
||||||
"account.getCollectibleEmojiStatuses",
|
"account.getCollectibleEmojiStatuses",
|
||||||
"account.addNoPaidMessagesException",
|
"account.addNoPaidMessagesException",
|
||||||
|
"account.getPaidMessagesRevenue",
|
||||||
"users.getUsers",
|
"users.getUsers",
|
||||||
"users.getFullUser",
|
"users.getFullUser",
|
||||||
"contacts.getContacts",
|
"contacts.getContacts",
|
||||||
|
|||||||
@ -103,7 +103,6 @@ $color-message-story-mention-to: #74bcff;
|
|||||||
--color-voice-transcribe-button: #e8f3ff;
|
--color-voice-transcribe-button: #e8f3ff;
|
||||||
--color-voice-transcribe-button-own: #cceebf;
|
--color-voice-transcribe-button-own: #cceebf;
|
||||||
|
|
||||||
--color-toast-action: #64D1FF;
|
|
||||||
--color-primary: #{$color-primary};
|
--color-primary: #{$color-primary};
|
||||||
--color-primary-shade: #{color.mix($color-primary, $color-black, 92%)};
|
--color-primary-shade: #{color.mix($color-primary, $color-black, 92%)};
|
||||||
--color-primary-shade-darker: #{color.mix($color-primary, $color-black, 84%)};
|
--color-primary-shade-darker: #{color.mix($color-primary, $color-black, 84%)};
|
||||||
|
|||||||
3
src/types/language.d.ts
vendored
3
src/types/language.d.ts
vendored
@ -1447,6 +1447,9 @@ export interface LangPair {
|
|||||||
'StoryTooltipReactionSent': undefined;
|
'StoryTooltipReactionSent': undefined;
|
||||||
'StarsNeededTextSendPaidMessages': undefined;
|
'StarsNeededTextSendPaidMessages': undefined;
|
||||||
'PaidMessageTransactionTotal': undefined;
|
'PaidMessageTransactionTotal': undefined;
|
||||||
|
'DescriptionRestrictedMedia': undefined;
|
||||||
|
'DescriptionScheduledPaidMediaNotAllowed': undefined;
|
||||||
|
'DescriptionScheduledPaidMessagesNotAllowed': undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LangPairWithVariables<V extends unknown = LangVariable> {
|
export interface LangPairWithVariables<V extends unknown = LangVariable> {
|
||||||
|
|||||||
@ -12,12 +12,12 @@ import {
|
|||||||
getChatAvatarHash,
|
getChatAvatarHash,
|
||||||
getChatTitle,
|
getChatTitle,
|
||||||
getMessageRecentReaction,
|
getMessageRecentReaction,
|
||||||
getMessageSenderName,
|
|
||||||
getPrivateChatUserId,
|
getPrivateChatUserId,
|
||||||
getUserFullName,
|
getUserFullName,
|
||||||
isChatChannel,
|
isChatChannel,
|
||||||
} from '../global/helpers';
|
} from '../global/helpers';
|
||||||
import { getIsChatMuted, getIsChatSilent, getShouldShowMessagePreview } from '../global/helpers/notifications';
|
import { getIsChatMuted, getIsChatSilent, getShouldShowMessagePreview } from '../global/helpers/notifications';
|
||||||
|
import { getMessageSenderName } from '../global/helpers/peers';
|
||||||
import {
|
import {
|
||||||
selectChat,
|
selectChat,
|
||||||
selectCurrentMessageList,
|
selectCurrentMessageList,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user