Monetization Statistics: Implement verification modal for withdraw button (#4929)
This commit is contained in:
parent
505f67674a
commit
09203ae76e
@ -77,6 +77,7 @@ export interface GramJsAppConfig extends LimitsConfig {
|
|||||||
group_transcribe_level_min?: number;
|
group_transcribe_level_min?: number;
|
||||||
new_noncontact_peers_require_premium_without_ownpremium?: boolean;
|
new_noncontact_peers_require_premium_without_ownpremium?: boolean;
|
||||||
channel_restrict_sponsored_level_min?: number;
|
channel_restrict_sponsored_level_min?: number;
|
||||||
|
channel_revenue_withdrawal_enabled?: boolean;
|
||||||
// Upload premium notifications
|
// Upload premium notifications
|
||||||
upload_premium_speedup_notify_period?: number;
|
upload_premium_speedup_notify_period?: number;
|
||||||
upload_premium_speedup_download?: number;
|
upload_premium_speedup_download?: number;
|
||||||
@ -161,5 +162,6 @@ export function buildAppConfig(json: GramJs.TypeJSONValue, hash: number): ApiApp
|
|||||||
bandwidthPremiumUploadSpeedup: appConfig.upload_premium_speedup_upload,
|
bandwidthPremiumUploadSpeedup: appConfig.upload_premium_speedup_upload,
|
||||||
bandwidthPremiumDownloadSpeedup: appConfig.upload_premium_speedup_download,
|
bandwidthPremiumDownloadSpeedup: appConfig.upload_premium_speedup_download,
|
||||||
channelRestrictAdsLevelMin: appConfig.channel_restrict_sponsored_level_min,
|
channelRestrictAdsLevelMin: appConfig.channel_restrict_sponsored_level_min,
|
||||||
|
isChannelRevenueWithdrawalEnabled: appConfig.channel_revenue_withdrawal_enabled,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import {
|
|||||||
Api as GramJs,
|
Api as GramJs,
|
||||||
sessions,
|
sessions,
|
||||||
} from '../../../lib/gramjs';
|
} from '../../../lib/gramjs';
|
||||||
import type { TwoFaParams } from '../../../lib/gramjs/client/2fa';
|
import type { TwoFaParams, TwoFaPasswordParams } from '../../../lib/gramjs/client/2fa';
|
||||||
import TelegramClient from '../../../lib/gramjs/client/TelegramClient';
|
import TelegramClient from '../../../lib/gramjs/client/TelegramClient';
|
||||||
import { Logger as GramJsLogger } from '../../../lib/gramjs/extensions/index';
|
import { Logger as GramJsLogger } from '../../../lib/gramjs/extensions/index';
|
||||||
|
|
||||||
@ -369,6 +369,10 @@ export function getTmpPassword(currentPassword: string, ttl?: number) {
|
|||||||
return client.getTmpPassword(currentPassword, ttl);
|
return client.getTmpPassword(currentPassword, ttl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getCurrentPassword(params: TwoFaPasswordParams) {
|
||||||
|
return client.getCurrentPassword(params);
|
||||||
|
}
|
||||||
|
|
||||||
export function abortChatRequests(params: { chatId: string; threadId?: ThreadId }) {
|
export function abortChatRequests(params: { chatId: string; threadId?: ThreadId }) {
|
||||||
const { chatId, threadId } = params;
|
const { chatId, threadId } = params;
|
||||||
const controller = CHAT_ABORT_CONTROLLERS.get(chatId);
|
const controller = CHAT_ABORT_CONTROLLERS.get(chatId);
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import {
|
|||||||
} from '../apiBuilders/statistics';
|
} from '../apiBuilders/statistics';
|
||||||
import { buildInputEntity, buildInputPeer } from '../gramjsBuilders';
|
import { buildInputEntity, buildInputPeer } from '../gramjsBuilders';
|
||||||
import { invokeRequest } from './client';
|
import { invokeRequest } from './client';
|
||||||
|
import { getPassword, onPasswordError } from './twoFaSettings';
|
||||||
|
|
||||||
export async function fetchChannelStatistics({
|
export async function fetchChannelStatistics({
|
||||||
chat, dcId,
|
chat, dcId,
|
||||||
@ -211,3 +212,32 @@ export async function fetchStoryPublicForwards({
|
|||||||
nextOffset: result.nextOffset,
|
nextOffset: result.nextOffset,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function loadMonetizationRevenueWithdrawalUrl({
|
||||||
|
chat, currentPassword,
|
||||||
|
}: { chat: ApiChat; currentPassword: string }) {
|
||||||
|
try {
|
||||||
|
const password = await getPassword(currentPassword);
|
||||||
|
|
||||||
|
if (!password || 'error' in password) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await invokeRequest(new GramJs.stats.GetBroadcastRevenueWithdrawalUrl({
|
||||||
|
channel: buildInputEntity(chat.id, chat.accessHash) as GramJs.InputChannel,
|
||||||
|
password,
|
||||||
|
}), {
|
||||||
|
shouldThrow: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (err: any) {
|
||||||
|
onPasswordError(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|||||||
@ -2,7 +2,9 @@ import { Api as GramJs, errors } from '../../../lib/gramjs';
|
|||||||
|
|
||||||
import { DEBUG } from '../../../config';
|
import { DEBUG } from '../../../config';
|
||||||
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
||||||
import { getTmpPassword, invokeRequest, updateTwoFaSettings } from './client';
|
import {
|
||||||
|
getCurrentPassword, getTmpPassword, invokeRequest, updateTwoFaSettings,
|
||||||
|
} from './client';
|
||||||
|
|
||||||
const ApiErrors: { [k: string]: string } = {
|
const ApiErrors: { [k: string]: string } = {
|
||||||
EMAIL_UNCONFIRMED: 'Email unconfirmed',
|
EMAIL_UNCONFIRMED: 'Email unconfirmed',
|
||||||
@ -11,6 +13,7 @@ const ApiErrors: { [k: string]: string } = {
|
|||||||
NEW_SETTINGS_INVALID: 'The new password settings are invalid',
|
NEW_SETTINGS_INVALID: 'The new password settings are invalid',
|
||||||
CODE_INVALID: 'Invalid Code',
|
CODE_INVALID: 'Invalid Code',
|
||||||
PASSWORD_HASH_INVALID: 'Invalid Password',
|
PASSWORD_HASH_INVALID: 'Invalid Password',
|
||||||
|
PASSWORD_MISSING: 'You must enable 2FA before executing this operation',
|
||||||
};
|
};
|
||||||
|
|
||||||
const emailCodeController: {
|
const emailCodeController: {
|
||||||
@ -45,6 +48,18 @@ export function getTemporaryPaymentPassword(password: string, ttl?: number) {
|
|||||||
return getTmpPassword(password, ttl);
|
return getTmpPassword(password, ttl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getPassword(password: string) {
|
||||||
|
try {
|
||||||
|
return getCurrentPassword({
|
||||||
|
currentPassword: password,
|
||||||
|
onPasswordCodeError: onPasswordError,
|
||||||
|
});
|
||||||
|
} catch (err: any) {
|
||||||
|
onPasswordError(err);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function checkPassword(currentPassword: string) {
|
export async function checkPassword(currentPassword: string) {
|
||||||
try {
|
try {
|
||||||
await updateTwoFaSettings({ isCheckPassword: true, currentPassword });
|
await updateTwoFaSettings({ isCheckPassword: true, currentPassword });
|
||||||
@ -134,3 +149,28 @@ function onError(err: Error) {
|
|||||||
message,
|
message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function onPasswordError(err: Error) {
|
||||||
|
let message: string;
|
||||||
|
|
||||||
|
if (err instanceof errors.PasswordModifiedError) {
|
||||||
|
const hours = Math.ceil(Number(err.seconds) / 60 / 60);
|
||||||
|
message = `Too many attempts. Try again in ${hours > 1 ? `${hours} hours` : 'an hour'}`;
|
||||||
|
} else {
|
||||||
|
message = ApiErrors[err.message];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!message) {
|
||||||
|
message = 'Unexpected Error';
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendApiUpdate({
|
||||||
|
'@type': 'updatePasswordError',
|
||||||
|
error: message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@ -210,6 +210,7 @@ export interface ApiAppConfig {
|
|||||||
bandwidthPremiumUploadSpeedup?: number;
|
bandwidthPremiumUploadSpeedup?: number;
|
||||||
bandwidthPremiumDownloadSpeedup?: number;
|
bandwidthPremiumDownloadSpeedup?: number;
|
||||||
channelRestrictAdsLevelMin?: number;
|
channelRestrictAdsLevelMin?: number;
|
||||||
|
isChannelRevenueWithdrawalEnabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApiConfig {
|
export interface ApiConfig {
|
||||||
|
|||||||
@ -481,6 +481,11 @@ export type ApiUpdateTwoFaError = {
|
|||||||
message: string;
|
message: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ApiUpdatePasswordError = {
|
||||||
|
'@type': 'updatePasswordError';
|
||||||
|
error: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type ApiUpdateNotifySettings = {
|
export type ApiUpdateNotifySettings = {
|
||||||
'@type': 'updateNotifySettings';
|
'@type': 'updateNotifySettings';
|
||||||
peerType: 'contact' | 'group' | 'broadcast';
|
peerType: 'contact' | 'group' | 'broadcast';
|
||||||
@ -776,7 +781,7 @@ export type ApiUpdate = (
|
|||||||
ApiUpdateRecentStickers | ApiUpdateSavedGifs | ApiUpdateNewScheduledMessage | ApiUpdateMoveStickerSetToTop |
|
ApiUpdateRecentStickers | ApiUpdateSavedGifs | ApiUpdateNewScheduledMessage | ApiUpdateMoveStickerSetToTop |
|
||||||
ApiUpdateScheduledMessageSendSucceeded | ApiUpdateScheduledMessage |
|
ApiUpdateScheduledMessageSendSucceeded | ApiUpdateScheduledMessage |
|
||||||
ApiUpdateDeleteScheduledMessages | ApiUpdateResetMessages | ApiUpdateMessageTranslations |
|
ApiUpdateDeleteScheduledMessages | ApiUpdateResetMessages | ApiUpdateMessageTranslations |
|
||||||
ApiUpdateTwoFaError | ApiUpdateTwoFaStateWaitCode | ApiUpdateWebViewResultSent |
|
ApiUpdateTwoFaError | ApiUpdatePasswordError | ApiUpdateTwoFaStateWaitCode | ApiUpdateWebViewResultSent |
|
||||||
ApiUpdateNotifySettings | ApiUpdateNotifyExceptions | ApiUpdatePeerBlocked | ApiUpdatePrivacy |
|
ApiUpdateNotifySettings | ApiUpdateNotifyExceptions | ApiUpdatePeerBlocked | ApiUpdatePrivacy |
|
||||||
ApiUpdateServerTimeOffset | ApiUpdateShowInvite | ApiUpdateMessageReactions | ApiUpdateSavedReactionTags |
|
ApiUpdateServerTimeOffset | ApiUpdateShowInvite | ApiUpdateMessageReactions | ApiUpdateSavedReactionTags |
|
||||||
ApiUpdateGroupCallParticipants | ApiUpdateGroupCallConnection | ApiUpdateGroupCall | ApiUpdateGroupCallStreams |
|
ApiUpdateGroupCallParticipants | ApiUpdateGroupCallConnection | ApiUpdateGroupCall | ApiUpdateGroupCallStreams |
|
||||||
|
|||||||
@ -32,6 +32,7 @@ export { default as StarsTransactionInfoModal } from '../components/modals/stars
|
|||||||
|
|
||||||
export { default as AboutAdsModal } from '../components/common/AboutAdsModal';
|
export { default as AboutAdsModal } from '../components/common/AboutAdsModal';
|
||||||
export { default as AboutMonetizationModal } from '../components/common/AboutMonetizationModal';
|
export { default as AboutMonetizationModal } from '../components/common/AboutMonetizationModal';
|
||||||
|
export { default as VerificationMonetizationModal } from '../components/common/VerificationMonetizationModal';
|
||||||
export { default as ReportAdModal } from '../components/modals/reportAd/ReportAdModal';
|
export { default as ReportAdModal } from '../components/modals/reportAd/ReportAdModal';
|
||||||
export { default as CalendarModal } from '../components/common/CalendarModal';
|
export { default as CalendarModal } from '../components/common/CalendarModal';
|
||||||
export { default as DeleteMessageModal } from '../components/common/DeleteMessageModal';
|
export { default as DeleteMessageModal } from '../components/common/DeleteMessageModal';
|
||||||
|
|||||||
@ -0,0 +1,18 @@
|
|||||||
|
import type { FC } from '../../lib/teact/teact';
|
||||||
|
import React from '../../lib/teact/teact';
|
||||||
|
|
||||||
|
import type { OwnProps } from './VerificationMonetizationModal';
|
||||||
|
|
||||||
|
import { Bundles } from '../../util/moduleLoader';
|
||||||
|
|
||||||
|
import useModuleLoader from '../../hooks/useModuleLoader';
|
||||||
|
|
||||||
|
const VerificationMonetizationModalAsync: FC<OwnProps> = (props) => {
|
||||||
|
const { isOpen } = props;
|
||||||
|
const VerificationMonetizationModal = useModuleLoader(Bundles.Extra, 'VerificationMonetizationModal', !isOpen);
|
||||||
|
|
||||||
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||||
|
return VerificationMonetizationModal ? <VerificationMonetizationModal {...props} /> : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default VerificationMonetizationModalAsync;
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
.root {
|
||||||
|
:global(.modal-dialog) {
|
||||||
|
max-width: 25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
}
|
||||||
87
src/components/common/VerificationMonetizationModal.tsx
Normal file
87
src/components/common/VerificationMonetizationModal.tsx
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import type { FC } from '../../lib/teact/teact';
|
||||||
|
import React, {
|
||||||
|
memo,
|
||||||
|
useState,
|
||||||
|
} from '../../lib/teact/teact';
|
||||||
|
import { getActions } from '../../global';
|
||||||
|
|
||||||
|
import buildClassName from '../../util/buildClassName';
|
||||||
|
|
||||||
|
import useLastCallback from '../../hooks/useLastCallback';
|
||||||
|
import useOldLang from '../../hooks/useOldLang';
|
||||||
|
|
||||||
|
import Modal from '../ui/Modal';
|
||||||
|
import PasswordForm from './PasswordForm';
|
||||||
|
|
||||||
|
import styles from './VerificationMonetizationModal.module.scss';
|
||||||
|
|
||||||
|
export type OwnProps = {
|
||||||
|
isOpen: boolean;
|
||||||
|
onClose: NoneToVoidFunction;
|
||||||
|
chatId: string;
|
||||||
|
passwordHint?: string;
|
||||||
|
error?: string;
|
||||||
|
isLoading?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const VerificationMonetizationModal: FC<OwnProps> = ({
|
||||||
|
isOpen,
|
||||||
|
chatId,
|
||||||
|
onClose,
|
||||||
|
passwordHint,
|
||||||
|
error,
|
||||||
|
isLoading,
|
||||||
|
}) => {
|
||||||
|
const {
|
||||||
|
clearMonetizationInfo, loadMonetizationRevenueWithdrawalUrl,
|
||||||
|
} = getActions();
|
||||||
|
|
||||||
|
const lang = useOldLang();
|
||||||
|
|
||||||
|
const [shouldShowPassword, setShouldShowPassword] = useState(false);
|
||||||
|
|
||||||
|
const handleSubmit = useLastCallback((password: string) => {
|
||||||
|
loadMonetizationRevenueWithdrawalUrl({
|
||||||
|
chatId,
|
||||||
|
currentPassword: password,
|
||||||
|
onSuccess: () => {
|
||||||
|
onClose();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleClearError = useLastCallback(() => {
|
||||||
|
clearMonetizationInfo();
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isOpen={isOpen}
|
||||||
|
hasCloseButton
|
||||||
|
title={lang('EnterPassword')}
|
||||||
|
className={styles.root}
|
||||||
|
contentClassName={styles.content}
|
||||||
|
onClose={onClose}
|
||||||
|
>
|
||||||
|
<div className={buildClassName(styles.content, 'settings-content password-form custom-scroll')}>
|
||||||
|
<div className="settings-item pt-0">
|
||||||
|
<PasswordForm
|
||||||
|
shouldShowSubmit
|
||||||
|
placeholder={lang('Password')}
|
||||||
|
error={error && lang(error)}
|
||||||
|
description={lang('Channel.OwnershipTransfer.EnterPasswordText')}
|
||||||
|
clearError={handleClearError}
|
||||||
|
isLoading={isLoading}
|
||||||
|
hint={passwordHint}
|
||||||
|
isPasswordVisible={shouldShowPassword}
|
||||||
|
shouldResetValue={isOpen}
|
||||||
|
onChangePasswordVisibility={setShouldShowPassword}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(VerificationMonetizationModal);
|
||||||
@ -5,19 +5,22 @@ import { getActions, withGlobal } from '../../../global';
|
|||||||
|
|
||||||
import type { ApiChannelMonetizationStatistics, StatisticsGraph } from '../../../api/types';
|
import type { ApiChannelMonetizationStatistics, StatisticsGraph } from '../../../api/types';
|
||||||
|
|
||||||
import { FRAGMENT_ADS_URL } from '../../../config';
|
|
||||||
import { selectChat, selectChatFullInfo, selectTabState } from '../../../global/selectors';
|
import { selectChat, selectChatFullInfo, selectTabState } from '../../../global/selectors';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
|
import renderText from '../../common/helpers/renderText';
|
||||||
|
|
||||||
import useFlag from '../../../hooks/useFlag';
|
import useFlag from '../../../hooks/useFlag';
|
||||||
import useForceUpdate from '../../../hooks/useForceUpdate';
|
import useForceUpdate from '../../../hooks/useForceUpdate';
|
||||||
import useLang from '../../../hooks/useLang';
|
import useLang from '../../../hooks/useLang';
|
||||||
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
import useOldLang from '../../../hooks/useOldLang';
|
import useOldLang from '../../../hooks/useOldLang';
|
||||||
|
|
||||||
import AboutMonetizationModal from '../../common/AboutMonetizationModal.async';
|
import AboutMonetizationModal from '../../common/AboutMonetizationModal.async';
|
||||||
import Icon from '../../common/icons/Icon';
|
import Icon from '../../common/icons/Icon';
|
||||||
import SafeLink from '../../common/SafeLink';
|
import SafeLink from '../../common/SafeLink';
|
||||||
|
import VerificationMonetizationModal from '../../common/VerificationMonetizationModal.async';
|
||||||
import Button from '../../ui/Button';
|
import Button from '../../ui/Button';
|
||||||
|
import ConfirmDialog from '../../ui/ConfirmDialog';
|
||||||
import Link from '../../ui/Link';
|
import Link from '../../ui/Link';
|
||||||
import Loading from '../../ui/Loading';
|
import Loading from '../../ui/Loading';
|
||||||
import StatisticsOverview from './StatisticsOverview';
|
import StatisticsOverview from './StatisticsOverview';
|
||||||
@ -47,29 +50,46 @@ type StateProps = {
|
|||||||
chatId: string;
|
chatId: string;
|
||||||
dcId?: number;
|
dcId?: number;
|
||||||
statistics?: ApiChannelMonetizationStatistics;
|
statistics?: ApiChannelMonetizationStatistics;
|
||||||
canCollect?: boolean;
|
isCreator?: boolean;
|
||||||
|
isChannelRevenueWithdrawalEnabled?: boolean;
|
||||||
|
hasPassword?: boolean;
|
||||||
|
passwordHint?: string;
|
||||||
|
error?: string;
|
||||||
|
isLoading?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MonetizationStatistics = ({
|
const MonetizationStatistics = ({
|
||||||
chatId,
|
chatId,
|
||||||
dcId,
|
dcId,
|
||||||
statistics,
|
statistics,
|
||||||
canCollect,
|
isCreator,
|
||||||
|
isChannelRevenueWithdrawalEnabled,
|
||||||
|
hasPassword,
|
||||||
|
passwordHint,
|
||||||
|
error,
|
||||||
|
isLoading,
|
||||||
}: StateProps) => {
|
}: StateProps) => {
|
||||||
const { loadChannelMonetizationStatistics } = getActions();
|
const { loadChannelMonetizationStatistics, loadPasswordInfo } = getActions();
|
||||||
const oldLang = useOldLang();
|
const oldLang = useOldLang();
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
|
|
||||||
// eslint-disable-next-line no-null/no-null
|
// eslint-disable-next-line no-null/no-null
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const [isReady, setIsReady] = useState(false);
|
const [isReady, setIsReady] = useState(false);
|
||||||
const loadedCharts = useRef<string[]>([]);
|
const loadedCharts = useRef<string[]>([]);
|
||||||
const forceUpdate = useForceUpdate();
|
const forceUpdate = useForceUpdate();
|
||||||
const [isAboutMonetizationModalOpen, openAboutMonetizationModal, closeAboutMonetizationModal] = useFlag(false);
|
const [isAboutMonetizationModalOpen, openAboutMonetizationModal, closeAboutMonetizationModal] = useFlag(false);
|
||||||
const hasAvailableBalance = Boolean(statistics?.balances?.availableBalance !== 0);
|
const [
|
||||||
|
isVerificationMonetizationModalOpen, openVerificationMonetizationModal, closeVerificationMonetizationModal,
|
||||||
|
] = useFlag(false);
|
||||||
|
const [isConfirmPasswordDialogOpen, openConfirmPasswordDialogOpen, closeConfirmPasswordDialogOpen] = useFlag();
|
||||||
|
const availableBalance = statistics?.balances?.availableBalance;
|
||||||
|
const canWithdraw = isCreator && isChannelRevenueWithdrawalEnabled && Boolean(availableBalance);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (chatId) {
|
if (chatId) {
|
||||||
loadChannelMonetizationStatistics({ chatId });
|
loadChannelMonetizationStatistics({ chatId });
|
||||||
|
loadPasswordInfo();
|
||||||
}
|
}
|
||||||
}, [chatId, loadChannelMonetizationStatistics]);
|
}, [chatId, loadChannelMonetizationStatistics]);
|
||||||
|
|
||||||
@ -86,7 +106,7 @@ const MonetizationStatistics = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MONETIZATION_GRAPHS.forEach((name, index: number) => {
|
MONETIZATION_GRAPHS.filter(Boolean).forEach((name, index: number) => {
|
||||||
const graph = statistics[name as keyof typeof statistics];
|
const graph = statistics[name as keyof typeof statistics];
|
||||||
const isAsync = typeof graph === 'string';
|
const isAsync = typeof graph === 'string';
|
||||||
|
|
||||||
@ -115,7 +135,6 @@ const MonetizationStatistics = ({
|
|||||||
}, [isReady, statistics, oldLang, chatId, dcId, forceUpdate]);
|
}, [isReady, statistics, oldLang, chatId, dcId, forceUpdate]);
|
||||||
|
|
||||||
function renderAvailableReward() {
|
function renderAvailableReward() {
|
||||||
const availableBalance = statistics?.balances?.availableBalance;
|
|
||||||
const [integerTonPart, decimalTonPart] = availableBalance ? availableBalance.toFixed(4).split('.') : [0];
|
const [integerTonPart, decimalTonPart] = availableBalance ? availableBalance.toFixed(4).split('.') : [0];
|
||||||
const [integerUsdPart, decimalUsdPart] = availableBalance
|
const [integerUsdPart, decimalUsdPart] = availableBalance
|
||||||
&& statistics?.usdRate ? (availableBalance * statistics.usdRate).toFixed(2).split('.') : [0];
|
&& statistics?.usdRate ? (availableBalance * statistics.usdRate).toFixed(2).split('.') : [0];
|
||||||
@ -172,6 +191,14 @@ const MonetizationStatistics = ({
|
|||||||
);
|
);
|
||||||
}, [lang, oldLang]);
|
}, [lang, oldLang]);
|
||||||
|
|
||||||
|
const verificationMonetizationHandler = useLastCallback(() => {
|
||||||
|
if (hasPassword) {
|
||||||
|
openVerificationMonetizationModal();
|
||||||
|
} else {
|
||||||
|
openConfirmPasswordDialogOpen();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (!isReady || !statistics) {
|
if (!isReady || !statistics) {
|
||||||
return <Loading />;
|
return <Loading />;
|
||||||
}
|
}
|
||||||
@ -190,29 +217,49 @@ const MonetizationStatistics = ({
|
|||||||
{!loadedCharts.current.length && <Loading />}
|
{!loadedCharts.current.length && <Loading />}
|
||||||
|
|
||||||
<div ref={containerRef} className={styles.section}>
|
<div ref={containerRef} className={styles.section}>
|
||||||
{MONETIZATION_GRAPHS.map((graph) => (
|
{MONETIZATION_GRAPHS.filter(Boolean).map((graph) => (
|
||||||
<div key={graph} className={buildClassName(styles.graph, styles.hidden)} />
|
<div key={graph} className={buildClassName(styles.graph, styles.hidden)} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{hasAvailableBalance && (
|
<div className={styles.section}>
|
||||||
<div className={styles.section}>
|
{oldLang('lng_channel_earn_balance_title')}
|
||||||
{oldLang('lng_channel_earn_balance_title')}
|
|
||||||
|
|
||||||
{renderAvailableReward()}
|
{renderAvailableReward()}
|
||||||
|
|
||||||
<Button size="smaller" type="button" href={FRAGMENT_ADS_URL} disabled={canCollect && hasAvailableBalance}>
|
<Button
|
||||||
{oldLang('MonetizationWithdraw')}
|
size="smaller"
|
||||||
</Button>
|
type="button"
|
||||||
|
onClick={verificationMonetizationHandler}
|
||||||
|
disabled={!canWithdraw}
|
||||||
|
>
|
||||||
|
{oldLang('MonetizationWithdraw')}
|
||||||
|
</Button>
|
||||||
|
|
||||||
<div className={styles.textBottom}>{rewardsText}</div>
|
<div className={styles.textBottom}>{rewardsText}</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
|
|
||||||
<AboutMonetizationModal
|
<AboutMonetizationModal
|
||||||
isOpen={isAboutMonetizationModalOpen}
|
isOpen={isAboutMonetizationModalOpen}
|
||||||
onClose={closeAboutMonetizationModal}
|
onClose={closeAboutMonetizationModal}
|
||||||
/>
|
/>
|
||||||
|
<VerificationMonetizationModal
|
||||||
|
chatId={chatId}
|
||||||
|
isOpen={isVerificationMonetizationModalOpen}
|
||||||
|
onClose={closeVerificationMonetizationModal}
|
||||||
|
passwordHint={passwordHint}
|
||||||
|
error={error}
|
||||||
|
isLoading={isLoading}
|
||||||
|
/>
|
||||||
|
<ConfirmDialog
|
||||||
|
isOnlyConfirm
|
||||||
|
isOpen={isConfirmPasswordDialogOpen}
|
||||||
|
onClose={closeConfirmPasswordDialogOpen}
|
||||||
|
confirmHandler={closeConfirmPasswordDialogOpen}
|
||||||
|
confirmLabel={lang('OK')}
|
||||||
|
>
|
||||||
|
<p>{renderText(oldLang('Monetization.Withdraw.Error.Text'), ['br'])}</p>
|
||||||
|
</ConfirmDialog>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -220,18 +267,38 @@ const MonetizationStatistics = ({
|
|||||||
export default memo(withGlobal(
|
export default memo(withGlobal(
|
||||||
(global): StateProps => {
|
(global): StateProps => {
|
||||||
const tabState = selectTabState(global);
|
const tabState = selectTabState(global);
|
||||||
|
const {
|
||||||
|
settings: {
|
||||||
|
byKey: {
|
||||||
|
hasPassword,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
twoFaSettings: {
|
||||||
|
hint: passwordHint,
|
||||||
|
},
|
||||||
|
} = global;
|
||||||
|
const isLoading = global.monetizationInfo?.isLoading;
|
||||||
|
const error = global.monetizationInfo?.error;
|
||||||
const monetizationStatistics = tabState.monetizationStatistics;
|
const monetizationStatistics = tabState.monetizationStatistics;
|
||||||
const chatId = monetizationStatistics && monetizationStatistics.chatId;
|
const chatId = monetizationStatistics && monetizationStatistics.chatId;
|
||||||
const chat = chatId ? selectChat(global, chatId) : undefined;
|
const chat = chatId ? selectChat(global, chatId) : undefined;
|
||||||
const canCollect = chat && chat.isCreator;
|
|
||||||
const dcId = selectChatFullInfo(global, chatId!)?.statisticsDcId;
|
const dcId = selectChatFullInfo(global, chatId!)?.statisticsDcId;
|
||||||
|
const isCreator = Boolean(chat?.isCreator);
|
||||||
|
|
||||||
const statistics = tabState.statistics.monetization;
|
const statistics = tabState.statistics.monetization;
|
||||||
|
|
||||||
|
const isChannelRevenueWithdrawalEnabled = global.appConfig?.isChannelRevenueWithdrawalEnabled;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chatId: chatId!,
|
chatId: chatId!,
|
||||||
dcId,
|
dcId,
|
||||||
statistics,
|
statistics,
|
||||||
canCollect,
|
isCreator,
|
||||||
|
isChannelRevenueWithdrawalEnabled,
|
||||||
|
hasPassword,
|
||||||
|
passwordHint,
|
||||||
|
error,
|
||||||
|
isLoading,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(MonetizationStatistics));
|
)(MonetizationStatistics));
|
||||||
|
|||||||
@ -38,5 +38,6 @@ import './apiUpdaters/symbols';
|
|||||||
import './apiUpdaters/misc';
|
import './apiUpdaters/misc';
|
||||||
import './apiUpdaters/settings';
|
import './apiUpdaters/settings';
|
||||||
import './apiUpdaters/twoFaSettings';
|
import './apiUpdaters/twoFaSettings';
|
||||||
|
import './apiUpdaters/password';
|
||||||
import './apiUpdaters/calls';
|
import './apiUpdaters/calls';
|
||||||
import './apiUpdaters/payments';
|
import './apiUpdaters/payments';
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import type { ActionReturnType } from '../../types';
|
||||||
|
|
||||||
import { areDeepEqual } from '../../../util/areDeepEqual';
|
import { areDeepEqual } from '../../../util/areDeepEqual';
|
||||||
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
||||||
import { callApi } from '../../../api/gramjs';
|
import { callApi } from '../../../api/gramjs';
|
||||||
@ -5,6 +7,7 @@ import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
|||||||
import {
|
import {
|
||||||
updateChannelMonetizationStatistics,
|
updateChannelMonetizationStatistics,
|
||||||
updateMessageStatistics,
|
updateMessageStatistics,
|
||||||
|
updateMonetizationInfo,
|
||||||
updateStatistics,
|
updateStatistics,
|
||||||
updateStatisticsGraph,
|
updateStatisticsGraph,
|
||||||
updateStoryStatistics,
|
updateStoryStatistics,
|
||||||
@ -224,3 +227,41 @@ addActionHandler('loadStoryPublicForwards', async (global, actions, payload): Pr
|
|||||||
}, tabId);
|
}, tabId);
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addActionHandler('loadMonetizationRevenueWithdrawalUrl', async (global, actions, payload): Promise<void> => {
|
||||||
|
const {
|
||||||
|
chatId, currentPassword, onSuccess, tabId = getCurrentTabId(),
|
||||||
|
} = payload;
|
||||||
|
|
||||||
|
global = updateMonetizationInfo(global, { isLoading: true, error: undefined });
|
||||||
|
setGlobal(global);
|
||||||
|
|
||||||
|
const chat = selectChat(global, chatId);
|
||||||
|
if (!chat) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await callApi('loadMonetizationRevenueWithdrawalUrl', { chat, currentPassword });
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
global = getGlobal();
|
||||||
|
global = updateMonetizationInfo(global, { isLoading: false });
|
||||||
|
setGlobal(global);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
onSuccess();
|
||||||
|
actions.openUrl({
|
||||||
|
url: result.url,
|
||||||
|
shouldSkipModal: true,
|
||||||
|
tabId,
|
||||||
|
ignoreDeepLinks: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
addActionHandler('clearMonetizationInfo', (global): ActionReturnType => {
|
||||||
|
return updateMonetizationInfo(global, { error: undefined });
|
||||||
|
});
|
||||||
|
|||||||
20
src/global/actions/apiUpdaters/password.ts
Normal file
20
src/global/actions/apiUpdaters/password.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import type { ActionReturnType } from '../../types';
|
||||||
|
|
||||||
|
import { addActionHandler } from '../../index';
|
||||||
|
|
||||||
|
addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
||||||
|
switch (update['@type']) {
|
||||||
|
case 'updatePasswordError': {
|
||||||
|
return {
|
||||||
|
...global,
|
||||||
|
monetizationInfo: {
|
||||||
|
...global.monetizationInfo,
|
||||||
|
isLoading: false,
|
||||||
|
error: update.error,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
@ -297,6 +297,8 @@ export const INITIAL_GLOBAL_STATE: GlobalState = {
|
|||||||
isMinimized: false,
|
isMinimized: false,
|
||||||
isHidden: false,
|
isHidden: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
monetizationInfo: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const INITIAL_TAB_STATE: TabState = {
|
export const INITIAL_TAB_STATE: TabState = {
|
||||||
|
|||||||
@ -12,4 +12,5 @@ export * from './payments';
|
|||||||
export * from './statistics';
|
export * from './statistics';
|
||||||
export * from './stories';
|
export * from './stories';
|
||||||
export * from './translations';
|
export * from './translations';
|
||||||
|
export * from './password';
|
||||||
export * from './general';
|
export * from './general';
|
||||||
|
|||||||
14
src/global/reducers/password.ts
Normal file
14
src/global/reducers/password.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import type { GlobalState } from '../types';
|
||||||
|
|
||||||
|
export function updateMonetizationInfo<T extends GlobalState>(
|
||||||
|
global: T,
|
||||||
|
update: GlobalState['monetizationInfo'],
|
||||||
|
): T {
|
||||||
|
return {
|
||||||
|
...global,
|
||||||
|
monetizationInfo: {
|
||||||
|
...global.monetizationInfo,
|
||||||
|
...update,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -872,6 +872,11 @@ export type GlobalState = {
|
|||||||
waitingEmailCodeLength?: number;
|
waitingEmailCodeLength?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
monetizationInfo: {
|
||||||
|
isLoading?: boolean;
|
||||||
|
error?: string;
|
||||||
|
};
|
||||||
|
|
||||||
attachmentSettings: {
|
attachmentSettings: {
|
||||||
shouldCompress: boolean;
|
shouldCompress: boolean;
|
||||||
shouldSendGrouped: boolean;
|
shouldSendGrouped: boolean;
|
||||||
@ -1285,6 +1290,7 @@ export interface ActionPayloads {
|
|||||||
updatePerformanceSettings: Partial<PerformanceType>;
|
updatePerformanceSettings: Partial<PerformanceType>;
|
||||||
loadPasswordInfo: undefined;
|
loadPasswordInfo: undefined;
|
||||||
clearTwoFaError: undefined;
|
clearTwoFaError: undefined;
|
||||||
|
clearMonetizationInfo: undefined;
|
||||||
updatePassword: {
|
updatePassword: {
|
||||||
currentPassword: string;
|
currentPassword: string;
|
||||||
password: string;
|
password: string;
|
||||||
@ -1825,6 +1831,12 @@ export interface ActionPayloads {
|
|||||||
chatId: string;
|
chatId: string;
|
||||||
} & WithTabId;
|
} & WithTabId;
|
||||||
|
|
||||||
|
loadMonetizationRevenueWithdrawalUrl: {
|
||||||
|
chatId: string;
|
||||||
|
currentPassword: string;
|
||||||
|
onSuccess: VoidFunction;
|
||||||
|
} & WithTabId;
|
||||||
|
|
||||||
// ui
|
// ui
|
||||||
dismissDialog: WithTabId | undefined;
|
dismissDialog: WithTabId | undefined;
|
||||||
setNewChatMembersDialogState: {
|
setNewChatMembersDialogState: {
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import type TelegramClient from './TelegramClient';
|
import type TelegramClient from './TelegramClient';
|
||||||
|
|
||||||
|
import errors from '../errors';
|
||||||
// eslint-disable-next-line import/no-named-default
|
// eslint-disable-next-line import/no-named-default
|
||||||
import { default as Api } from '../tl/api';
|
import { default as Api } from '../tl/api';
|
||||||
|
|
||||||
import { generateRandomBytes } from '../Helpers';
|
import { generateRandomBytes } from '../Helpers';
|
||||||
import { computeCheck, computeDigest } from '../Password';
|
import { computeCheck, computeDigest } from '../Password';
|
||||||
import errors from '../errors';
|
|
||||||
|
|
||||||
export interface TwoFaParams {
|
export interface TwoFaParams {
|
||||||
isCheckPassword?: boolean;
|
isCheckPassword?: boolean;
|
||||||
@ -15,7 +17,13 @@ export interface TwoFaParams {
|
|||||||
onEmailCodeError?: (err: Error) => void;
|
onEmailCodeError?: (err: Error) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TwoFaPasswordParams {
|
||||||
|
currentPassword?: string;
|
||||||
|
onPasswordCodeError?: (err: Error) => void;
|
||||||
|
}
|
||||||
|
|
||||||
export type TmpPasswordResult = Api.account.TmpPassword | { error: string } | undefined;
|
export type TmpPasswordResult = Api.account.TmpPassword | { error: string } | undefined;
|
||||||
|
export type PasswordResult = Api.account.Password | { error: string } | undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the 2FA settings of the logged in user.
|
* Changes the 2FA settings of the logged in user.
|
||||||
@ -147,3 +155,29 @@ export async function getTmpPassword(client: TelegramClient, currentPassword: st
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getCurrentPassword(
|
||||||
|
client: TelegramClient,
|
||||||
|
{
|
||||||
|
currentPassword,
|
||||||
|
onPasswordCodeError,
|
||||||
|
}: TwoFaPasswordParams,
|
||||||
|
) {
|
||||||
|
const pwd = await client.invoke(new Api.account.GetPassword());
|
||||||
|
|
||||||
|
if (!pwd) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return currentPassword ? await computeCheck(pwd, currentPassword!) : new Api.InputCheckPasswordEmpty();
|
||||||
|
} catch (err: any) {
|
||||||
|
if (err instanceof errors.PasswordModifiedError) {
|
||||||
|
return onPasswordCodeError!(err);
|
||||||
|
} else if (err.message === 'PASSWORD_HASH_INVALID') {
|
||||||
|
return { error: err.message };
|
||||||
|
} else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
6
src/lib/gramjs/client/TelegramClient.d.ts
vendored
6
src/lib/gramjs/client/TelegramClient.d.ts
vendored
@ -1,4 +1,6 @@
|
|||||||
import type { TmpPasswordResult, TwoFaParams, updateTwoFaSettings } from './2fa';
|
import type {
|
||||||
|
PasswordResult, TmpPasswordResult, TwoFaParams, TwoFaPasswordParams, updateTwoFaSettings,
|
||||||
|
} from './2fa';
|
||||||
import type { BotAuthParams, UserAuthParams } from './auth';
|
import type { BotAuthParams, UserAuthParams } from './auth';
|
||||||
import type { downloadFile, DownloadFileParams } from './downloadFile';
|
import type { downloadFile, DownloadFileParams } from './downloadFile';
|
||||||
import type { uploadFile, UploadFileParams } from './uploadFile';
|
import type { uploadFile, UploadFileParams } from './uploadFile';
|
||||||
@ -24,6 +26,8 @@ declare class TelegramClient {
|
|||||||
|
|
||||||
async getTmpPassword(currentPassword: string, ttl?: number): Promise<TmpPasswordResult>;
|
async getTmpPassword(currentPassword: string, ttl?: number): Promise<TmpPasswordResult>;
|
||||||
|
|
||||||
|
async getCurrentPassword(Params: TwoFaPasswordParams): Promise<PasswordResult>;
|
||||||
|
|
||||||
setPingCallback(callback: () => Promise<void>);
|
setPingCallback(callback: () => Promise<void>);
|
||||||
|
|
||||||
setForceHttpTransport: (forceHttpTransport: boolean) => void;
|
setForceHttpTransport: (forceHttpTransport: boolean) => void;
|
||||||
|
|||||||
@ -26,6 +26,7 @@ const { uploadFile } = require('./uploadFile');
|
|||||||
const {
|
const {
|
||||||
updateTwoFaSettings,
|
updateTwoFaSettings,
|
||||||
getTmpPassword,
|
getTmpPassword,
|
||||||
|
getCurrentPassword,
|
||||||
} = require('./2fa');
|
} = require('./2fa');
|
||||||
const RequestState = require('../network/RequestState');
|
const RequestState = require('../network/RequestState');
|
||||||
const Deferred = require('../../../util/Deferred').default;
|
const Deferred = require('../../../util/Deferred').default;
|
||||||
@ -1118,6 +1119,10 @@ class TelegramClient {
|
|||||||
return getTmpPassword(this, currentPassword, ttl);
|
return getTmpPassword(this, currentPassword, ttl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getCurrentPassword(currentPassword) {
|
||||||
|
return getCurrentPassword(this, currentPassword);
|
||||||
|
}
|
||||||
|
|
||||||
// event region
|
// event region
|
||||||
addEventHandler(callback, event) {
|
addEventHandler(callback, event) {
|
||||||
this._eventBuilders.push([event, callback]);
|
this._eventBuilders.push([event, callback]);
|
||||||
|
|||||||
@ -101,6 +101,16 @@ class EmailUnconfirmedError extends BadRequestError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PasswordModifiedError extends BadRequestError {
|
||||||
|
constructor(args) {
|
||||||
|
const seconds = Number(args.capture || 0);
|
||||||
|
super(`The password was modified less than 24 hours ago, try again in ${seconds} seconds.`);
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
this.message = `The password was modified less than 24 hours ago, try again in ${seconds} seconds.`;
|
||||||
|
this.seconds = seconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const rpcErrorRe = [
|
const rpcErrorRe = [
|
||||||
[/FILE_MIGRATE_(\d+)/, FileMigrateError],
|
[/FILE_MIGRATE_(\d+)/, FileMigrateError],
|
||||||
[/FLOOD_TEST_PHONE_WAIT_(\d+)/, FloodTestPhoneWaitError],
|
[/FLOOD_TEST_PHONE_WAIT_(\d+)/, FloodTestPhoneWaitError],
|
||||||
@ -112,6 +122,7 @@ const rpcErrorRe = [
|
|||||||
[/USER_MIGRATE_(\d+)/, UserMigrateError],
|
[/USER_MIGRATE_(\d+)/, UserMigrateError],
|
||||||
[/NETWORK_MIGRATE_(\d+)/, NetworkMigrateError],
|
[/NETWORK_MIGRATE_(\d+)/, NetworkMigrateError],
|
||||||
[/EMAIL_UNCONFIRMED_(\d+)/, EmailUnconfirmedError],
|
[/EMAIL_UNCONFIRMED_(\d+)/, EmailUnconfirmedError],
|
||||||
|
[/PASSWORD_TOO_FRESH_(\d+)/, PasswordModifiedError],
|
||||||
[/^Timeout$/, TimedOutError],
|
[/^Timeout$/, TimedOutError],
|
||||||
];
|
];
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@ -126,4 +137,5 @@ module.exports = {
|
|||||||
NetworkMigrateError,
|
NetworkMigrateError,
|
||||||
MsgWaitError,
|
MsgWaitError,
|
||||||
EmailUnconfirmedError,
|
EmailUnconfirmedError,
|
||||||
|
PasswordModifiedError,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1624,8 +1624,8 @@ bots.setBotInfo#10cf3123 flags:# bot:flags.2?InputUser lang_code:string name:fla
|
|||||||
bots.canSendMessage#1359f4e6 bot:InputUser = Bool;
|
bots.canSendMessage#1359f4e6 bot:InputUser = Bool;
|
||||||
bots.allowSendMessage#f132e3ef bot:InputUser = Updates;
|
bots.allowSendMessage#f132e3ef bot:InputUser = Updates;
|
||||||
bots.invokeWebViewCustomMethod#87fc5e7 bot:InputUser custom_method:string params:DataJSON = DataJSON;
|
bots.invokeWebViewCustomMethod#87fc5e7 bot:InputUser custom_method:string params:DataJSON = DataJSON;
|
||||||
bots.getPreviewMedias#a2a5594d bot:InputUser = Vector<BotPreviewMedia>;
|
|
||||||
bots.getPopularAppBots#c2510192 offset:string limit:int = bots.PopularAppBots;
|
bots.getPopularAppBots#c2510192 offset:string limit:int = bots.PopularAppBots;
|
||||||
|
bots.getPreviewMedias#a2a5594d bot:InputUser = Vector<BotPreviewMedia>;
|
||||||
payments.getPaymentForm#37148dbb flags:# invoice:InputInvoice theme_params:flags.0?DataJSON = payments.PaymentForm;
|
payments.getPaymentForm#37148dbb flags:# invoice:InputInvoice theme_params:flags.0?DataJSON = payments.PaymentForm;
|
||||||
payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt;
|
payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt;
|
||||||
payments.validateRequestedInfo#b6c8f12b flags:# save:flags.0?true invoice:InputInvoice info:PaymentRequestedInfo = payments.ValidatedRequestedInfo;
|
payments.validateRequestedInfo#b6c8f12b flags:# save:flags.0?true invoice:InputInvoice info:PaymentRequestedInfo = payments.ValidatedRequestedInfo;
|
||||||
@ -1676,6 +1676,7 @@ stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel ms
|
|||||||
stats.getStoryStats#374fef40 flags:# dark:flags.0?true peer:InputPeer id:int = stats.StoryStats;
|
stats.getStoryStats#374fef40 flags:# dark:flags.0?true peer:InputPeer id:int = stats.StoryStats;
|
||||||
stats.getStoryPublicForwards#a6437ef6 peer:InputPeer id:int offset:string limit:int = stats.PublicForwards;
|
stats.getStoryPublicForwards#a6437ef6 peer:InputPeer id:int offset:string limit:int = stats.PublicForwards;
|
||||||
stats.getBroadcastRevenueStats#75dfb671 flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastRevenueStats;
|
stats.getBroadcastRevenueStats#75dfb671 flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastRevenueStats;
|
||||||
|
stats.getBroadcastRevenueWithdrawalUrl#2a65ef73 channel:InputChannel password:InputCheckPasswordSRP = stats.BroadcastRevenueWithdrawalUrl;
|
||||||
chatlists.exportChatlistInvite#8472478e chatlist:InputChatlist title:string peers:Vector<InputPeer> = chatlists.ExportedChatlistInvite;
|
chatlists.exportChatlistInvite#8472478e chatlist:InputChatlist title:string peers:Vector<InputPeer> = chatlists.ExportedChatlistInvite;
|
||||||
chatlists.deleteExportedInvite#719c5c5e chatlist:InputChatlist slug:string = Bool;
|
chatlists.deleteExportedInvite#719c5c5e chatlist:InputChatlist slug:string = Bool;
|
||||||
chatlists.editExportedInvite#653db63d flags:# chatlist:InputChatlist slug:string title:flags.1?string peers:flags.2?Vector<InputPeer> = ExportedChatlistInvite;
|
chatlists.editExportedInvite#653db63d flags:# chatlist:InputChatlist slug:string title:flags.1?string peers:flags.2?Vector<InputPeer> = ExportedChatlistInvite;
|
||||||
|
|||||||
@ -282,6 +282,7 @@
|
|||||||
"stats.getStoryStats",
|
"stats.getStoryStats",
|
||||||
"stats.getStoryPublicForwards",
|
"stats.getStoryPublicForwards",
|
||||||
"stats.loadAsyncGraph",
|
"stats.loadAsyncGraph",
|
||||||
|
"stats.getBroadcastRevenueWithdrawalUrl",
|
||||||
"messages.getAttachMenuBots",
|
"messages.getAttachMenuBots",
|
||||||
"messages.getAttachMenuBot",
|
"messages.getAttachMenuBot",
|
||||||
"messages.toggleBotInAttachMenu",
|
"messages.toggleBotInAttachMenu",
|
||||||
|
|||||||
@ -20,6 +20,7 @@ const READABLE_ERROR_MESSAGES: Record<string, string> = {
|
|||||||
MEDIA_NEW_INVALID: 'Failed to replace new media',
|
MEDIA_NEW_INVALID: 'Failed to replace new media',
|
||||||
MESSAGE_NOT_MODIFIED: 'Message not modified. The new content is identical to the current one.',
|
MESSAGE_NOT_MODIFIED: 'Message not modified. The new content is identical to the current one.',
|
||||||
MEDIA_INVALID: 'Media invalid',
|
MEDIA_INVALID: 'Media invalid',
|
||||||
|
PASSWORD_HASH_INVALID: 'Incorrect password',
|
||||||
PHOTO_EXT_INVALID: 'The extension of the photo is invalid',
|
PHOTO_EXT_INVALID: 'The extension of the photo is invalid',
|
||||||
PHOTO_INVALID_DIMENSIONS: 'The photo dimensions are invalid',
|
PHOTO_INVALID_DIMENSIONS: 'The photo dimensions are invalid',
|
||||||
PHOTO_SAVE_FILE_INVALID: 'Internal issues, try again later',
|
PHOTO_SAVE_FILE_INVALID: 'Internal issues, try again later',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user