Unique Gift: Support withdrawal (#5534)
This commit is contained in:
parent
e40d669ea3
commit
d5f214fa9a
@ -19,7 +19,7 @@ import type {
|
||||
|
||||
import { numberToHexColor } from '../../../util/colors';
|
||||
import { pick } from '../../../util/iteratees';
|
||||
import { addDocumentToLocalDb } from '../helpers';
|
||||
import { addDocumentToLocalDb } from '../helpers/localDb';
|
||||
import { buildApiPhoto, buildApiThumbnailFromStripped } from './common';
|
||||
import { omitVirtualClassFields } from './helpers';
|
||||
import { buildApiDocument, buildApiWebDocument, buildVideoFromDocument } from './messageContent';
|
||||
|
||||
@ -25,7 +25,8 @@ import type {
|
||||
|
||||
import { pick, pickTruthy } from '../../../util/iteratees';
|
||||
import { getServerTime, getServerTimeOffset } from '../../../util/serverTime';
|
||||
import { addPhotoToLocalDb, addUserToLocalDb, serializeBytes } from '../helpers';
|
||||
import { addPhotoToLocalDb, addUserToLocalDb } from '../helpers/localDb';
|
||||
import { serializeBytes } from '../helpers/misc';
|
||||
import {
|
||||
buildApiBotVerification, buildApiFormattedText, buildApiPhoto, buildApiUsernames, buildAvatarPhotoId,
|
||||
} from './common';
|
||||
|
||||
@ -8,7 +8,7 @@ import type {
|
||||
} from '../../types';
|
||||
|
||||
import { numberToHexColor } from '../../../util/colors';
|
||||
import { addDocumentToLocalDb } from '../helpers';
|
||||
import { addDocumentToLocalDb } from '../helpers/localDb';
|
||||
import { buildApiFormattedText } from './common';
|
||||
import { getApiChatIdFromMtpPeer } from './peers';
|
||||
import { buildStickerFromDocument } from './symbols';
|
||||
@ -129,7 +129,7 @@ export function buildApiStarGiftAttribute(attribute: GramJs.TypeStarGiftAttribut
|
||||
export function buildApiSavedStarGift(userStarGift: GramJs.SavedStarGift, peerId: string): ApiSavedStarGift {
|
||||
const {
|
||||
gift, date, convertStars, fromId, message, msgId, nameHidden, unsaved, upgradeStars, transferStars, canUpgrade,
|
||||
savedId,
|
||||
savedId, canExportAt,
|
||||
} = userStarGift;
|
||||
|
||||
const inputGift: ApiInputSavedStarGift | undefined = savedId && peerId
|
||||
@ -150,5 +150,6 @@ export function buildApiSavedStarGift(userStarGift: GramJs.SavedStarGift, peerId
|
||||
transferStars: transferStars?.toJSNumber(),
|
||||
inputGift,
|
||||
savedId: savedId?.toString(),
|
||||
canExportAt,
|
||||
};
|
||||
}
|
||||
|
||||
@ -32,8 +32,9 @@ import { SUPPORTED_PHOTO_CONTENT_TYPES, SUPPORTED_VIDEO_CONTENT_TYPES, VIDEO_WEB
|
||||
import { generateWaveform } from '../../../util/generateWaveform';
|
||||
import { pick } from '../../../util/iteratees';
|
||||
import {
|
||||
addMediaToLocalDb, addStoryToLocalDb, type MediaRepairContext, serializeBytes,
|
||||
} from '../helpers';
|
||||
addMediaToLocalDb, addStoryToLocalDb, type MediaRepairContext,
|
||||
} from '../helpers/localDb';
|
||||
import { serializeBytes } from '../helpers/misc';
|
||||
import {
|
||||
buildApiFormattedText,
|
||||
buildApiMessageEntity,
|
||||
|
||||
@ -58,9 +58,8 @@ import { buildPeer } from '../gramjsBuilders';
|
||||
import {
|
||||
addPhotoToLocalDb,
|
||||
type MediaRepairContext,
|
||||
resolveMessageApiChatId,
|
||||
serializeBytes,
|
||||
} from '../helpers';
|
||||
} from '../helpers/localDb';
|
||||
import { resolveMessageApiChatId, serializeBytes } from '../helpers/misc';
|
||||
import { buildApiCallDiscardReason } from './calls';
|
||||
import {
|
||||
buildApiFormattedText,
|
||||
|
||||
@ -22,7 +22,7 @@ import {
|
||||
buildCollectionByCallback, omit, omitUndefined, pick,
|
||||
} from '../../../util/iteratees';
|
||||
import { getServerTime } from '../../../util/serverTime';
|
||||
import { addUserToLocalDb } from '../helpers';
|
||||
import { addUserToLocalDb } from '../helpers/localDb';
|
||||
import { omitVirtualClassFields } from './helpers';
|
||||
import { buildApiDocument, buildMessageTextContent } from './messageContent';
|
||||
import { buildApiPeerId, getApiChatIdFromMtpPeer } from './peers';
|
||||
|
||||
@ -29,7 +29,7 @@ import type {
|
||||
BoughtPaidMedia,
|
||||
} from '../../types';
|
||||
|
||||
import { addWebDocumentToLocalDb } from '../helpers';
|
||||
import { addWebDocumentToLocalDb } from '../helpers/localDb';
|
||||
import { buildApiStarsSubscriptionPricing } from './chats';
|
||||
import { buildApiMessageEntity } from './common';
|
||||
import { buildApiStarGift } from './gifts';
|
||||
|
||||
@ -37,7 +37,7 @@ import {
|
||||
|
||||
import { CHANNEL_ID_LENGTH, DEFAULT_STATUS_ICON_ID } from '../../../config';
|
||||
import { pick } from '../../../util/iteratees';
|
||||
import { deserializeBytes } from '../helpers';
|
||||
import { deserializeBytes } from '../helpers/misc';
|
||||
import localDb from '../localDb';
|
||||
|
||||
function checkIfChannelId(id: string) {
|
||||
|
||||
@ -1,42 +1,11 @@
|
||||
import { Api as GramJs } from '../../lib/gramjs';
|
||||
import { Api as GramJs } from '../../../lib/gramjs';
|
||||
|
||||
import type { RepairInfo } from './localDb';
|
||||
|
||||
import { buildApiPeerId, getApiChatIdFromMtpPeer } from './apiBuilders/peers';
|
||||
import localDb from './localDb';
|
||||
|
||||
const LOG_BACKGROUND = '#111111DD';
|
||||
const LOG_PREFIX_COLOR = '#E4D00A';
|
||||
const LOG_SUFFIX = {
|
||||
INVOKE: '#49DBF5',
|
||||
BEACON: '#F549DB',
|
||||
RESPONSE: '#6887F7',
|
||||
CONNECTING: '#E4D00A',
|
||||
CONNECTED: '#26D907',
|
||||
'CONNECTING ERROR': '#D1191C',
|
||||
'INVOKE ERROR': '#D1191C',
|
||||
UPDATE: '#0DD151',
|
||||
'UNEXPECTED UPDATE': '#9C9C9C',
|
||||
'UNEXPECTED RESPONSE': '#D1191C',
|
||||
};
|
||||
import { buildApiPeerId, getApiChatIdFromMtpPeer } from '../apiBuilders/peers';
|
||||
import localDb, { type RepairInfo } from '../localDb';
|
||||
|
||||
export type MessageRepairContext = Pick<GramJs.TypeMessage, 'peerId' | 'id'>;
|
||||
export type MediaRepairContext = MessageRepairContext;
|
||||
|
||||
export function resolveMessageApiChatId(mtpMessage: GramJs.TypeMessage) {
|
||||
if (!(mtpMessage instanceof GramJs.Message || mtpMessage instanceof GramJs.MessageService)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return getApiChatIdFromMtpPeer(mtpMessage.peerId);
|
||||
}
|
||||
|
||||
export function isChatFolder(
|
||||
filter?: GramJs.TypeDialogFilter,
|
||||
): filter is GramJs.DialogFilter | GramJs.DialogFilterChatlist {
|
||||
return filter instanceof GramJs.DialogFilter || filter instanceof GramJs.DialogFilterChatlist;
|
||||
}
|
||||
|
||||
export function addMessageToLocalDb(message: GramJs.TypeMessage | GramJs.TypeSponsoredMessage) {
|
||||
if (message instanceof GramJs.Message) {
|
||||
if (message.media) addMediaToLocalDb(message.media, message);
|
||||
@ -204,33 +173,3 @@ export function addUserToLocalDb(user: GramJs.User) {
|
||||
export function addWebDocumentToLocalDb(webDocument: GramJs.TypeWebDocument) {
|
||||
localDb.webDocuments[webDocument.url] = webDocument;
|
||||
}
|
||||
|
||||
export function serializeBytes(value: Buffer) {
|
||||
return String.fromCharCode(...value);
|
||||
}
|
||||
|
||||
export function deserializeBytes(value: string) {
|
||||
return Buffer.from(value, 'binary');
|
||||
}
|
||||
|
||||
export function log(suffix: keyof typeof LOG_SUFFIX, ...data: any) {
|
||||
/* eslint-disable max-len */
|
||||
/* eslint-disable no-console */
|
||||
const func = suffix === 'UNEXPECTED RESPONSE' ? console.error
|
||||
: suffix === 'INVOKE ERROR' || suffix === 'UNEXPECTED UPDATE' ? console.warn : console.log;
|
||||
/* eslint-enable no-console */
|
||||
func(
|
||||
`%cGramJS%c${suffix}`,
|
||||
`color: ${LOG_PREFIX_COLOR}; background: ${LOG_BACKGROUND}; padding: 0.25rem; border-radius: 0.25rem;`,
|
||||
`color: ${LOG_SUFFIX[suffix]}; background: ${LOG_BACKGROUND}; padding: 0.25rem; border-radius: 0.25rem; margin-left: 0.25rem;`,
|
||||
...data,
|
||||
);
|
||||
/* eslint-enable max-len */
|
||||
}
|
||||
|
||||
export function isResponseUpdate<T extends GramJs.AnyRequest>(result: T['__response']): result is GramJs.TypeUpdate {
|
||||
return result instanceof GramJs.UpdatesTooLong || result instanceof GramJs.UpdateShortMessage
|
||||
|| result instanceof GramJs.UpdateShortChatMessage || result instanceof GramJs.UpdateShort
|
||||
|| result instanceof GramJs.UpdatesCombined || result instanceof GramJs.Updates
|
||||
|| result instanceof GramJs.UpdateShortSentMessage;
|
||||
}
|
||||
179
src/api/gramjs/helpers/misc.ts
Normal file
179
src/api/gramjs/helpers/misc.ts
Normal file
@ -0,0 +1,179 @@
|
||||
import { Api as GramJs, errors } from '../../../lib/gramjs';
|
||||
|
||||
import type { RegularLangKey } from '../../../types/language';
|
||||
import type { RegularLangFnParameters } from '../../../util/localization';
|
||||
|
||||
import { DEBUG } from '../../../config';
|
||||
import {
|
||||
DAY, getDays, getHours, getMinutes, HOUR, MINUTE,
|
||||
} from '../../../util/dates/units';
|
||||
import { getApiChatIdFromMtpPeer } from '../apiBuilders/peers';
|
||||
|
||||
const LOG_BACKGROUND = '#111111DD';
|
||||
const LOG_PREFIX_COLOR = '#E4D00A';
|
||||
const LOG_SUFFIX = {
|
||||
INVOKE: '#49DBF5',
|
||||
BEACON: '#F549DB',
|
||||
RESPONSE: '#6887F7',
|
||||
CONNECTING: '#E4D00A',
|
||||
CONNECTED: '#26D907',
|
||||
'CONNECTING ERROR': '#D1191C',
|
||||
'INVOKE ERROR': '#D1191C',
|
||||
UPDATE: '#0DD151',
|
||||
'UNEXPECTED UPDATE': '#9C9C9C',
|
||||
'UNEXPECTED RESPONSE': '#D1191C',
|
||||
};
|
||||
|
||||
const ERROR_KEYS: Record<string, RegularLangKey> = {
|
||||
PHONE_NUMBER_INVALID: 'ErrorPhoneNumberInvalid',
|
||||
PHONE_CODE_INVALID: 'ErrorCodeInvalid',
|
||||
PASSWORD_HASH_INVALID: 'ErrorIncorrectPassword',
|
||||
PHONE_PASSWORD_FLOOD: 'ErrorPasswordFlood',
|
||||
PHONE_NUMBER_BANNED: 'ErrorPhoneBanned',
|
||||
EMAIL_UNCONFIRMED: 'ErrorEmailUnconfirmed',
|
||||
EMAIL_HASH_EXPIRED: 'ErrorEmailHashExpired',
|
||||
NEW_SALT_INVALID: 'ErrorNewSaltInvalid',
|
||||
SRP_PASSWORD_CHANGED: 'ErrorPasswordChanged',
|
||||
CODE_INVALID: 'ErrorEmailCodeInvalid',
|
||||
PASSWORD_MISSING: 'ErrorPasswordMissing',
|
||||
};
|
||||
|
||||
export type MessageRepairContext = Pick<GramJs.TypeMessage, 'peerId' | 'id'>;
|
||||
export type MediaRepairContext = MessageRepairContext;
|
||||
|
||||
export type WrappedError<T extends Error = Error> = {
|
||||
messageKey: RegularLangFnParameters;
|
||||
errorMessage?: string;
|
||||
error: T;
|
||||
};
|
||||
|
||||
export function resolveMessageApiChatId(mtpMessage: GramJs.TypeMessage) {
|
||||
if (!(mtpMessage instanceof GramJs.Message || mtpMessage instanceof GramJs.MessageService)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return getApiChatIdFromMtpPeer(mtpMessage.peerId);
|
||||
}
|
||||
|
||||
export function isChatFolder(
|
||||
filter?: GramJs.TypeDialogFilter,
|
||||
): filter is GramJs.DialogFilter | GramJs.DialogFilterChatlist {
|
||||
return filter instanceof GramJs.DialogFilter || filter instanceof GramJs.DialogFilterChatlist;
|
||||
}
|
||||
|
||||
export function serializeBytes(value: Buffer) {
|
||||
return String.fromCharCode(...value);
|
||||
}
|
||||
|
||||
export function deserializeBytes(value: string) {
|
||||
return Buffer.from(value, 'binary');
|
||||
}
|
||||
|
||||
export function log(suffix: keyof typeof LOG_SUFFIX, ...data: any) {
|
||||
/* eslint-disable max-len */
|
||||
/* eslint-disable no-console */
|
||||
const func = suffix === 'UNEXPECTED RESPONSE' ? console.error
|
||||
: suffix === 'INVOKE ERROR' || suffix === 'UNEXPECTED UPDATE' ? console.warn : console.log;
|
||||
/* eslint-enable no-console */
|
||||
func(
|
||||
`%cGramJS%c${suffix}`,
|
||||
`color: ${LOG_PREFIX_COLOR}; background: ${LOG_BACKGROUND}; padding: 0.25rem; border-radius: 0.25rem;`,
|
||||
`color: ${LOG_SUFFIX[suffix]}; background: ${LOG_BACKGROUND}; padding: 0.25rem; border-radius: 0.25rem; margin-left: 0.25rem;`,
|
||||
...data,
|
||||
);
|
||||
/* eslint-enable max-len */
|
||||
}
|
||||
|
||||
export function isResponseUpdate<T extends GramJs.AnyRequest>(result: T['__response']): result is GramJs.TypeUpdate {
|
||||
return result instanceof GramJs.UpdatesTooLong || result instanceof GramJs.UpdateShortMessage
|
||||
|| result instanceof GramJs.UpdateShortChatMessage || result instanceof GramJs.UpdateShort
|
||||
|| result instanceof GramJs.UpdatesCombined || result instanceof GramJs.Updates
|
||||
|| result instanceof GramJs.UpdateShortSentMessage;
|
||||
}
|
||||
|
||||
export function checkErrorType(error: unknown): error is Error {
|
||||
if (!(error instanceof Error)) {
|
||||
// eslint-disable-next-line no-console
|
||||
if (DEBUG) console.warn('Unexpected error type', error);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function wrapError<T extends Error>(error: T): WrappedError<T> {
|
||||
let messageKey: RegularLangFnParameters | undefined;
|
||||
|
||||
const errorMessage = error instanceof errors.RPCError ? error.errorMessage : undefined;
|
||||
|
||||
if (error instanceof errors.FloodWaitError) {
|
||||
messageKey = {
|
||||
key: 'ErrorFloodTime',
|
||||
variables: { time: formatWait(error.seconds) },
|
||||
};
|
||||
} else if (error instanceof errors.PasswordFreshError) {
|
||||
messageKey = {
|
||||
key: 'ErrorPasswordFresh',
|
||||
variables: { time: formatWait(error.seconds) },
|
||||
};
|
||||
} else if (error instanceof errors.RPCError) {
|
||||
messageKey = {
|
||||
key: ERROR_KEYS[error.errorMessage],
|
||||
};
|
||||
}
|
||||
|
||||
if (!messageKey) {
|
||||
if (error.message) {
|
||||
messageKey = {
|
||||
key: 'ErrorUnexpectedMessage',
|
||||
variables: { error: error.message },
|
||||
};
|
||||
} else {
|
||||
messageKey = {
|
||||
key: 'ErrorUnexpected',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
messageKey,
|
||||
errorMessage,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
function formatWait(seconds: number): RegularLangFnParameters {
|
||||
if (seconds < MINUTE) {
|
||||
return {
|
||||
key: 'Seconds',
|
||||
variables: { count: seconds },
|
||||
options: { pluralValue: seconds },
|
||||
};
|
||||
}
|
||||
|
||||
if (seconds < HOUR) {
|
||||
const minutes = getMinutes(seconds);
|
||||
return {
|
||||
key: 'Minutes',
|
||||
variables: { count: minutes },
|
||||
options: { pluralValue: minutes },
|
||||
};
|
||||
}
|
||||
|
||||
if (seconds < DAY) {
|
||||
const hours = getHours(seconds);
|
||||
return {
|
||||
key: 'Hours',
|
||||
variables: { count: hours },
|
||||
options: { pluralValue: hours },
|
||||
};
|
||||
}
|
||||
|
||||
const days = getDays(seconds);
|
||||
|
||||
return {
|
||||
key: 'Days',
|
||||
variables: { count: days },
|
||||
options: { pluralValue: days },
|
||||
};
|
||||
}
|
||||
@ -1,7 +1,3 @@
|
||||
import { FloodWaitError, RPCError } from '../../../lib/gramjs/errors';
|
||||
|
||||
import type { RegularLangKey } from '../../../types/language';
|
||||
import type { RegularLangFnParameters } from '../../../util/localization';
|
||||
import type {
|
||||
ApiUpdateAuthorizationState,
|
||||
ApiUpdateAuthorizationStateType,
|
||||
@ -9,17 +5,9 @@ import type {
|
||||
ApiUserFullInfo,
|
||||
} from '../../types';
|
||||
|
||||
import { DEBUG } from '../../../config';
|
||||
import { wrapError } from '../helpers/misc';
|
||||
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
||||
|
||||
const ApiErrors: Record<string, RegularLangKey> = {
|
||||
PHONE_NUMBER_INVALID: 'ErrorPhoneNumberInvalid',
|
||||
PHONE_CODE_INVALID: 'ErrorCodeInvalid',
|
||||
PASSWORD_HASH_INVALID: 'ErrorIncorrectPassword',
|
||||
PHONE_PASSWORD_FLOOD: 'ErrorPasswordFlood',
|
||||
PHONE_NUMBER_BANNED: 'ErrorPhoneBanned',
|
||||
};
|
||||
|
||||
const authController: {
|
||||
resolve?: Function;
|
||||
reject?: Function;
|
||||
@ -87,36 +75,7 @@ export function onRequestQrCode(qrCode: { token: Buffer; expires: number }) {
|
||||
}
|
||||
|
||||
export function onAuthError(err: Error) {
|
||||
let messageKey: RegularLangFnParameters | undefined;
|
||||
|
||||
if (err instanceof FloodWaitError) {
|
||||
const hours = Math.ceil(Number(err.seconds) / 60 / 60);
|
||||
messageKey = {
|
||||
key: 'ErrorFlood',
|
||||
variables: { hour: hours },
|
||||
options: { pluralValue: hours },
|
||||
};
|
||||
} else if (err instanceof RPCError) {
|
||||
messageKey = {
|
||||
key: ApiErrors[err.errorMessage],
|
||||
};
|
||||
} else if (err.message) {
|
||||
messageKey = {
|
||||
key: 'ErrorUnexpectedMessage',
|
||||
variables: { error: err.message },
|
||||
};
|
||||
}
|
||||
|
||||
if (!messageKey) {
|
||||
messageKey = {
|
||||
key: 'ErrorUnexpected',
|
||||
};
|
||||
|
||||
if (DEBUG) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
const { messageKey } = wrapError(err);
|
||||
|
||||
sendApiUpdate({
|
||||
'@type': 'updateAuthorizationError',
|
||||
|
||||
@ -39,8 +39,8 @@ import {
|
||||
addPhotoToLocalDb,
|
||||
addUserToLocalDb,
|
||||
addWebDocumentToLocalDb,
|
||||
deserializeBytes,
|
||||
} from '../helpers';
|
||||
} from '../helpers/localDb';
|
||||
import { deserializeBytes } from '../helpers/misc';
|
||||
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
||||
import { invokeRequest } from './client';
|
||||
|
||||
|
||||
@ -69,8 +69,8 @@ import {
|
||||
} from '../gramjsBuilders';
|
||||
import {
|
||||
addPhotoToLocalDb,
|
||||
isChatFolder,
|
||||
} from '../helpers';
|
||||
} from '../helpers/localDb';
|
||||
import { isChatFolder } from '../helpers/misc';
|
||||
import { scheduleMutedChatUpdate } from '../scheduleUnmute';
|
||||
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
||||
import {
|
||||
|
||||
@ -3,7 +3,7 @@ import {
|
||||
sessions,
|
||||
type Update,
|
||||
} from '../../../lib/gramjs';
|
||||
import type { TwoFaParams, TwoFaPasswordParams } from '../../../lib/gramjs/client/2fa';
|
||||
import type { TwoFaParams } from '../../../lib/gramjs/client/2fa';
|
||||
import TelegramClient from '../../../lib/gramjs/client/TelegramClient';
|
||||
import { RPCError } from '../../../lib/gramjs/errors';
|
||||
import { Logger as GramJsLogger } from '../../../lib/gramjs/extensions/index';
|
||||
@ -30,8 +30,11 @@ import { buildApiStory } from '../apiBuilders/stories';
|
||||
import { buildApiUser, buildApiUserFullInfo } from '../apiBuilders/users';
|
||||
import { buildInputPeerFromLocalDb, getEntityTypeById } from '../gramjsBuilders';
|
||||
import {
|
||||
addStoryToLocalDb, addUserToLocalDb, isResponseUpdate, log,
|
||||
} from '../helpers';
|
||||
addStoryToLocalDb, addUserToLocalDb,
|
||||
} from '../helpers/localDb';
|
||||
import {
|
||||
isResponseUpdate, log,
|
||||
} from '../helpers/misc';
|
||||
import localDb, { clearLocalDb, type RepairInfo } from '../localDb';
|
||||
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
||||
import { processAndUpdateEntities, processMessageAndUpdateThreadInfo } from '../updates/entityProcessor';
|
||||
@ -376,8 +379,8 @@ export function getTmpPassword(currentPassword: string, ttl?: number) {
|
||||
return client.getTmpPassword(currentPassword, ttl);
|
||||
}
|
||||
|
||||
export function getCurrentPassword(params: TwoFaPasswordParams) {
|
||||
return client.getCurrentPassword(params);
|
||||
export function getCurrentPassword(currentPassword?: string) {
|
||||
return client.getCurrentPassword(currentPassword);
|
||||
}
|
||||
|
||||
export function abortChatRequests(params: { chatId: string; threadId?: ThreadId }) {
|
||||
|
||||
@ -89,7 +89,7 @@ import {
|
||||
import {
|
||||
deserializeBytes,
|
||||
resolveMessageApiChatId,
|
||||
} from '../helpers';
|
||||
} from '../helpers/misc';
|
||||
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
||||
import { processMessageAndUpdateThreadInfo } from '../updates/entityProcessor';
|
||||
import { processAffectedHistory, updateChannelState } from '../updates/updateManager';
|
||||
|
||||
@ -45,13 +45,15 @@ import {
|
||||
buildShippingInfo,
|
||||
} from '../gramjsBuilders';
|
||||
import {
|
||||
checkErrorType,
|
||||
deserializeBytes,
|
||||
serializeBytes,
|
||||
} from '../helpers';
|
||||
wrapError,
|
||||
} from '../helpers/misc';
|
||||
import localDb from '../localDb';
|
||||
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
||||
import { handleGramJsUpdate, invokeRequest } from './client';
|
||||
import { getTemporaryPaymentPassword } from './twoFaSettings';
|
||||
import { getPassword, getTemporaryPaymentPassword } from './twoFaSettings';
|
||||
|
||||
export async function validateRequestedInfo({
|
||||
inputInvoice,
|
||||
@ -689,3 +691,42 @@ export function upgradeGift({
|
||||
shouldReturnTrue: true,
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchStarGiftWithdrawalUrl({
|
||||
inputGift,
|
||||
password,
|
||||
}: {
|
||||
inputGift: ApiRequestInputSavedStarGift;
|
||||
password: string;
|
||||
}) {
|
||||
try {
|
||||
const passwordCheck = await getPassword(password);
|
||||
|
||||
if (!passwordCheck) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if ('error' in passwordCheck) {
|
||||
return passwordCheck;
|
||||
}
|
||||
|
||||
const result = await invokeRequest(new GramJs.payments.GetStarGiftWithdrawalUrl({
|
||||
stargift: buildInputSavedStarGift(inputGift),
|
||||
password: passwordCheck,
|
||||
}), {
|
||||
shouldThrow: true,
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return { url: result.url };
|
||||
} catch (err: unknown) {
|
||||
if (!checkErrorType(err)) return undefined;
|
||||
|
||||
return wrapError(err);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ import {
|
||||
buildInputPrivacyKey,
|
||||
buildInputPrivacyRules,
|
||||
} from '../gramjsBuilders';
|
||||
import { addPhotoToLocalDb } from '../helpers';
|
||||
import { addPhotoToLocalDb } from '../helpers/localDb';
|
||||
import localDb from '../localDb';
|
||||
import { getClient, invokeRequest, uploadFile } from './client';
|
||||
|
||||
|
||||
@ -16,8 +16,9 @@ import {
|
||||
buildStoryPublicForwards,
|
||||
} from '../apiBuilders/statistics';
|
||||
import { buildInputEntity, buildInputPeer } from '../gramjsBuilders';
|
||||
import { checkErrorType, wrapError } from '../helpers/misc';
|
||||
import { invokeRequest } from './client';
|
||||
import { getPassword, onPasswordError } from './twoFaSettings';
|
||||
import { getPassword } from './twoFaSettings';
|
||||
|
||||
export async function fetchChannelStatistics({
|
||||
chat, dcId,
|
||||
@ -216,7 +217,7 @@ export async function fetchStoryPublicForwards({
|
||||
};
|
||||
}
|
||||
|
||||
export async function loadMonetizationRevenueWithdrawalUrl({
|
||||
export async function fetchMonetizationRevenueWithdrawalUrl({
|
||||
peer, currentPassword,
|
||||
}: {
|
||||
peer: ApiPeer;
|
||||
@ -225,10 +226,14 @@ export async function loadMonetizationRevenueWithdrawalUrl({
|
||||
try {
|
||||
const password = await getPassword(currentPassword);
|
||||
|
||||
if (!password || 'error' in password) {
|
||||
if (!password) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if ('error' in password) {
|
||||
return password;
|
||||
}
|
||||
|
||||
const result = await invokeRequest(new GramJs.stats.GetBroadcastRevenueWithdrawalUrl({
|
||||
peer: buildInputPeer(peer.id, peer.accessHash),
|
||||
password,
|
||||
@ -240,9 +245,10 @@ export async function loadMonetizationRevenueWithdrawalUrl({
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (err: any) {
|
||||
onPasswordError(err);
|
||||
return { url: result.url };
|
||||
} catch (err: unknown) {
|
||||
if (!checkErrorType(err)) return undefined;
|
||||
return wrapError(err);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
@ -26,7 +26,8 @@ import {
|
||||
buildInputPrivacyRules,
|
||||
buildInputReaction,
|
||||
} from '../gramjsBuilders';
|
||||
import { addStoryToLocalDb, deserializeBytes } from '../helpers';
|
||||
import { addStoryToLocalDb } from '../helpers/localDb';
|
||||
import { deserializeBytes } from '../helpers/misc';
|
||||
import { invokeRequest } from './client';
|
||||
|
||||
export async function fetchAllStories({
|
||||
|
||||
@ -1,21 +1,11 @@
|
||||
import { Api as GramJs, errors } from '../../../lib/gramjs';
|
||||
import { Api as GramJs } from '../../../lib/gramjs';
|
||||
|
||||
import { DEBUG } from '../../../config';
|
||||
import { checkErrorType, wrapError } from '../helpers/misc';
|
||||
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
||||
import {
|
||||
getCurrentPassword, getTmpPassword, invokeRequest, updateTwoFaSettings,
|
||||
} from './client';
|
||||
|
||||
const ApiErrors: { [k: string]: string } = {
|
||||
EMAIL_UNCONFIRMED: 'Email unconfirmed',
|
||||
EMAIL_HASH_EXPIRED: 'Email hash expired',
|
||||
NEW_SALT_INVALID: 'The new salt is invalid',
|
||||
NEW_SETTINGS_INVALID: 'The new password settings are invalid',
|
||||
CODE_INVALID: 'Invalid Code',
|
||||
PASSWORD_HASH_INVALID: 'Invalid Password',
|
||||
PASSWORD_MISSING: 'You must enable 2FA before executing this operation',
|
||||
};
|
||||
|
||||
const emailCodeController: {
|
||||
resolve?: Function;
|
||||
reject?: Function;
|
||||
@ -45,18 +35,22 @@ function onRequestEmailCode(length: number) {
|
||||
}
|
||||
|
||||
export function getTemporaryPaymentPassword(password: string, ttl?: number) {
|
||||
return getTmpPassword(password, ttl);
|
||||
try {
|
||||
return getTmpPassword(password, ttl);
|
||||
} catch (err: unknown) {
|
||||
if (!checkErrorType(err)) return undefined;
|
||||
|
||||
return Promise.resolve(wrapError(err));
|
||||
}
|
||||
}
|
||||
|
||||
export function getPassword(password: string) {
|
||||
try {
|
||||
return getCurrentPassword({
|
||||
currentPassword: password,
|
||||
onPasswordCodeError: onPasswordError,
|
||||
});
|
||||
} catch (err: any) {
|
||||
onPasswordError(err);
|
||||
return undefined;
|
||||
return getCurrentPassword(password);
|
||||
} catch (err: unknown) {
|
||||
if (!checkErrorType(err)) return undefined;
|
||||
|
||||
return Promise.resolve(wrapError(err));
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,51 +120,10 @@ export function provideRecoveryEmailCode(code: string) {
|
||||
}
|
||||
|
||||
function onError(err: Error) {
|
||||
let message: string;
|
||||
|
||||
if (err instanceof errors.FloodWaitError) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
const wrappedError = wrapError(err);
|
||||
|
||||
sendApiUpdate({
|
||||
'@type': 'updateTwoFaError',
|
||||
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,
|
||||
messageKey: wrappedError.messageKey,
|
||||
});
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ import {
|
||||
buildMtpPeerId,
|
||||
getEntityTypeById,
|
||||
} from '../gramjsBuilders';
|
||||
import { addPhotoToLocalDb, addUserToLocalDb } from '../helpers';
|
||||
import { addPhotoToLocalDb, addUserToLocalDb } from '../helpers/localDb';
|
||||
import localDb from '../localDb';
|
||||
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
||||
import { invokeRequest } from './client';
|
||||
|
||||
@ -9,7 +9,7 @@ import { buildApiChatFromPreview } from '../apiBuilders/chats';
|
||||
import { buildPollFromMedia } from '../apiBuilders/messageContent';
|
||||
import { buildApiThreadInfoFromMessage } from '../apiBuilders/messages';
|
||||
import { buildApiUser } from '../apiBuilders/users';
|
||||
import { addChatToLocalDb, addMessageToLocalDb, addUserToLocalDb } from '../helpers';
|
||||
import { addChatToLocalDb, addMessageToLocalDb, addUserToLocalDb } from '../helpers/localDb';
|
||||
import { sendImmediateApiUpdate } from './apiUpdateEmitter';
|
||||
|
||||
const TYPE_USER = new Set(['User', 'UserEmpty']);
|
||||
|
||||
@ -71,11 +71,13 @@ import {
|
||||
import {
|
||||
addPhotoToLocalDb,
|
||||
addStoryToLocalDb,
|
||||
} from '../helpers/localDb';
|
||||
import {
|
||||
isChatFolder,
|
||||
log,
|
||||
resolveMessageApiChatId,
|
||||
serializeBytes,
|
||||
} from '../helpers';
|
||||
} from '../helpers/misc';
|
||||
import localDb from '../localDb';
|
||||
import { scheduleMutedChatUpdate, scheduleMutedTopicUpdate } from '../scheduleUnmute';
|
||||
import { sendApiUpdate } from './apiUpdateEmitter';
|
||||
|
||||
@ -7,7 +7,7 @@ import type { OriginMessageEvent, WorkerPayload } from './types';
|
||||
import { DEBUG } from '../../../config';
|
||||
import { DEBUG_LEVELS } from '../../../util/debugConsole';
|
||||
import { throttleWithTickEnd } from '../../../util/schedulers';
|
||||
import { log } from '../helpers';
|
||||
import { log } from '../helpers/misc';
|
||||
import { callApi, cancelApiProgress, initApi } from '../methods/init';
|
||||
|
||||
declare const self: WorkerGlobalScope;
|
||||
|
||||
@ -271,6 +271,7 @@ export interface ApiSavedStarGift {
|
||||
canUpgrade?: true;
|
||||
alreadyPaidUpgradeStars?: number;
|
||||
transferStars?: number;
|
||||
canExportAt?: number;
|
||||
isConverted?: boolean; // Local field, used for Action Message
|
||||
upgradeMsgId?: number; // Local field, used for Action Message
|
||||
}
|
||||
|
||||
@ -491,12 +491,7 @@ export type ApiUpdateSavedGifs = {
|
||||
|
||||
export type ApiUpdateTwoFaError = {
|
||||
'@type': 'updateTwoFaError';
|
||||
message: string;
|
||||
};
|
||||
|
||||
export type ApiUpdatePasswordError = {
|
||||
'@type': 'updatePasswordError';
|
||||
error: string;
|
||||
messageKey: RegularLangFnParameters;
|
||||
};
|
||||
|
||||
export type ApiUpdateNotifySettings = {
|
||||
@ -819,7 +814,7 @@ export type ApiUpdate = (
|
||||
ApiUpdateRecentStickers | ApiUpdateSavedGifs | ApiUpdateNewScheduledMessage | ApiUpdateMoveStickerSetToTop |
|
||||
ApiUpdateScheduledMessageSendSucceeded | ApiUpdateScheduledMessage | ApiUpdateStarPaymentStateCompleted |
|
||||
ApiUpdateDeleteScheduledMessages | ApiUpdateResetMessages | ApiUpdateMessageTranslations |
|
||||
ApiUpdateTwoFaError | ApiUpdatePasswordError | ApiUpdateTwoFaStateWaitCode | ApiUpdateWebViewResultSent |
|
||||
ApiUpdateTwoFaError | ApiUpdateTwoFaStateWaitCode | ApiUpdateWebViewResultSent |
|
||||
ApiUpdateNotifySettings | ApiUpdateNotifyExceptions | ApiUpdatePeerBlocked | ApiUpdatePrivacy |
|
||||
ApiUpdateServerTimeOffset | ApiUpdateMessageReactions | ApiUpdateSavedReactionTags |
|
||||
ApiUpdateGroupCallParticipants | ApiUpdateGroupCallConnection | ApiUpdateGroupCall | ApiUpdateGroupCallStreams |
|
||||
|
||||
1
src/assets/font-icons/fragment.svg
Normal file
1
src/assets/font-icons/fragment.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="none"><path d="M2.344 7.91c-.495 0-.639.78-.188.982l13.346 5.882c.33.149.71.149 1.041 0l13.346-5.882c.45-.203.307-.983-.188-.983zm-.64 3.034c-.568-.028-.882.494-.597.963l1.133 1.756.006.01.197.305.233.36L13.514 31.13c.514.75 1.411.586 1.425-.315l.028-13.37c0-.197-.02-.35-.086-.477a.75.75 0 0 0-.32-.303l-.067-.035-12.361-5.57a1.15 1.15 0 0 0-.43-.116m28.593 0q-.198.009-.43.115l-12.361 5.57c-.39.195-.473.415-.473.815l.028 13.371c.014.901.91 1.065 1.425.315l12.407-19.223c.285-.469-.029-.991-.596-.963" style="fill:#000;fill-opacity:1;stroke-width:0;stroke-dasharray:none"/></svg>
|
||||
|
After Width: | Height: | Size: 650 B |
@ -668,16 +668,23 @@
|
||||
"FavoriteStickers" = "Favorites";
|
||||
"PremiumStickers" = "Premium Stickers";
|
||||
"GroupStickers" = "Group Stickers";
|
||||
"ErrorSendRestrictedStickersAll" = "Sorry, sending stickers is not allowed in this group.";
|
||||
"ErrorPhoneNumberInvalid" = "Invalid phone number, please try again.";
|
||||
"ErrorCodeInvalid" = "Invalid code, please try again.";
|
||||
"ErrorIncorrectPassword" = "Invalid password, please try again.";
|
||||
"ErrorPasswordFlood" = "Too many attempts, please try again later.";
|
||||
"ErrorPhoneBanned" = "This phone number is banned.";
|
||||
"ErrorFlood_one" = "Too many attempts, please try again in {hour} hour";
|
||||
"ErrorFlood_other" = "Too many attempts, please try again in {hour} hours";
|
||||
"ErrorSendRestrictedStickersAll" = "Sorry, sending stickers is not allowed in this group";
|
||||
"ErrorPhoneNumberInvalid" = "Invalid phone number, please try again";
|
||||
"ErrorCodeInvalid" = "Invalid code, please try again";
|
||||
"ErrorEmailCodeInvalid" = "Invalid code, please try again";
|
||||
"ErrorIncorrectPassword" = "Invalid password, please try again";
|
||||
"ErrorPasswordFlood" = "Too many attempts, please try again later";
|
||||
"ErrorPhoneBanned" = "This phone number is banned";
|
||||
"ErrorFloodTime" = "Too many attempts, please try again in {time}";
|
||||
"ErrorPasswordFresh" = "The password was modified less than 24 hours ago, try again in {time}";
|
||||
"ErrorUnexpected" = "Unexpected error";
|
||||
"ErrorUnexpectedMessage" = "Unexpected error: {error}";
|
||||
"ErrorEmailUnconfirmed" = "Email not confirmed";
|
||||
"ErrorEmailHashExpired" = "Failed to confirm email, please try again";
|
||||
"ErrorNewSaltInvalid" = "Error validating password, please try again";
|
||||
"ErrorPasswordChanged" = "Password has been changed, please try again";
|
||||
"ErrorPasswordMissing" = "You must set 2FA password to use this feature";
|
||||
"ErrorUnspecified" = "Error";
|
||||
"NoStickers" = "No stickers yet";
|
||||
"ClearRecentEmoji" = "Clear recent emoji?";
|
||||
"TextFormatAddLinkTitle" = "Add Link";
|
||||
@ -1429,6 +1436,7 @@
|
||||
"GiftInfoViewUpgraded" = "View Upgraded Gift";
|
||||
"GiftInfoUpgradeBadge" = "upgrade";
|
||||
"GiftInfoUpgradeForFree" = "Upgrade For Free";
|
||||
"GiftInfoWithdraw" = "Withdraw";
|
||||
"GiftUpgradeUniqueTitle" = "Unique";
|
||||
"GiftUpgradeUniqueDescription" = "Turn your gift into a unique collectible that you can transfer or auction.";
|
||||
"GiftUpgradeTransferableTitle" = "Transferable";
|
||||
@ -1447,6 +1455,11 @@
|
||||
"GiftMakeUniqueDescription" = "Enable this to let {user} turn your gift into a unique collectible. {link}";
|
||||
"GiftMakeUniqueDescriptionChannel" = "Enable this to let admins of {peer} to turn your gift into a unique collectible. {link}";
|
||||
"GiftMakeUniqueLink" = "Learn More >";
|
||||
"GiftWithdrawTitle" = "Manage with Fragment";
|
||||
"GiftWithdrawDescription" = "You can use Fragment, a third-party service, to transfer **{gift}** to the TON blockchain. After that, you can manage it as an NFT with any TON wallet application.\n\nYou can also move such NFTs back to your Telegram account via Fragment.";
|
||||
"GiftWithdrawSubmit" = "Open Fragment";
|
||||
"GiftWithdrawWait_one" = "In {days} day, you'll be able to send this collectible to any TON blockchain address outside Telegram for sale or auction.";
|
||||
"GiftWithdrawWait_other" = "In {days} days, you'll be able to send this collectible to any TON blockchain address outside Telegram for sale or auction.";
|
||||
"StarsAmount" = "⭐️{amount}";
|
||||
"StarsAmountText_one" = "{amount} Star";
|
||||
"StarsAmountText_other" = "{amount} Stars";
|
||||
@ -1586,3 +1599,6 @@
|
||||
"ViewButtonGiftUnique" = "VIEW COLLECTIBLE";
|
||||
"AuthContinueOnThisLanguage" = "Continue in English";
|
||||
"Share" = "Share";
|
||||
"CheckPasswordTitle" = "Enter Password";
|
||||
"CheckPasswordPlaceholder" = "Password";
|
||||
"CheckPasswordDescription" = "Please enter your password to continue.";
|
||||
|
||||
@ -28,7 +28,7 @@ const INITIAL_KEYS: LangKey[] = [
|
||||
'ErrorIncorrectPassword',
|
||||
'ErrorPasswordFlood',
|
||||
'ErrorPhoneBanned',
|
||||
'ErrorFlood',
|
||||
'ErrorFloodTime',
|
||||
'ErrorUnexpected',
|
||||
'ErrorUnexpectedMessage',
|
||||
];
|
||||
|
||||
@ -31,10 +31,7 @@ export default {
|
||||
"ErrorIncorrectPassword": "Invalid password, please try again.",
|
||||
"ErrorPasswordFlood": "Too many attempts, please try again later.",
|
||||
"ErrorPhoneBanned": "This phone number is banned.",
|
||||
"ErrorFlood": {
|
||||
"one": "Too many attempts, please try again in {hour} hour",
|
||||
"other": "Too many attempts, please try again in {hour} hours"
|
||||
},
|
||||
"ErrorFloodTime": "Too many attempts, please try again in {time}.",
|
||||
"ErrorUnexpected": "Unexpected error",
|
||||
"ErrorUnexpectedMessage": "Unexpected error: {error}"
|
||||
} as Record<LangKey, LangPackStringValue>;
|
||||
|
||||
@ -9,3 +9,4 @@ export { default as GiftModal } from '../components/modals/gift/GiftModal';
|
||||
export { default as GiftRecipientPicker } from '../components/modals/gift/recipient/GiftRecipientPicker';
|
||||
export { default as GiftInfoModal } from '../components/modals/gift/info/GiftInfoModal';
|
||||
export { default as GiftUpgradeModal } from '../components/modals/gift/upgrade/GiftUpgradeModal';
|
||||
export { default as GiftWithdrawModal } from '../components/modals/gift/fragment/GiftWithdrawModal';
|
||||
|
||||
@ -8,8 +8,8 @@ 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);
|
||||
const { modal } = props;
|
||||
const VerificationMonetizationModal = useModuleLoader(Bundles.Extra, 'VerificationMonetizationModal', !modal);
|
||||
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
return VerificationMonetizationModal ? <VerificationMonetizationModal {...props} /> : undefined;
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
import type { FC } from '../../lib/teact/teact';
|
||||
import React, {
|
||||
memo,
|
||||
useState,
|
||||
} from '../../lib/teact/teact';
|
||||
import { getActions } from '../../global';
|
||||
import { getActions, withGlobal } from '../../global';
|
||||
|
||||
import type { TabState } from '../../global/types';
|
||||
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
|
||||
import useCurrentOrPrev from '../../hooks/useCurrentOrPrev';
|
||||
import useLang from '../../hooks/useLang';
|
||||
import useLastCallback from '../../hooks/useLastCallback';
|
||||
import useOldLang from '../../hooks/useOldLang';
|
||||
|
||||
import Modal from '../ui/Modal';
|
||||
import PasswordForm from './PasswordForm';
|
||||
@ -16,62 +18,63 @@ 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;
|
||||
modal: TabState['monetizationVerificationModal'];
|
||||
};
|
||||
|
||||
const VerificationMonetizationModal: FC<OwnProps> = ({
|
||||
isOpen,
|
||||
chatId,
|
||||
onClose,
|
||||
type StateProps = {
|
||||
passwordHint?: string;
|
||||
};
|
||||
|
||||
const VerificationMonetizationModal = ({
|
||||
modal,
|
||||
passwordHint,
|
||||
error,
|
||||
isLoading,
|
||||
}) => {
|
||||
}: OwnProps & StateProps) => {
|
||||
const {
|
||||
clearMonetizationInfo, loadMonetizationRevenueWithdrawalUrl,
|
||||
closeMonetizationVerificationModal, clearMonetizationVerificationError, processMonetizationRevenueWithdrawalUrl,
|
||||
} = getActions();
|
||||
|
||||
const lang = useOldLang();
|
||||
const isOpen = Boolean(modal);
|
||||
|
||||
const renderingModal = useCurrentOrPrev(modal);
|
||||
|
||||
const lang = useLang();
|
||||
|
||||
const [shouldShowPassword, setShouldShowPassword] = useState(false);
|
||||
|
||||
const handleSubmit = useLastCallback((password: string) => {
|
||||
loadMonetizationRevenueWithdrawalUrl({
|
||||
peerId: chatId,
|
||||
if (!renderingModal) return;
|
||||
processMonetizationRevenueWithdrawalUrl({
|
||||
peerId: renderingModal.chatId,
|
||||
currentPassword: password,
|
||||
onSuccess: () => {
|
||||
onClose();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
const handleClearError = useLastCallback(() => {
|
||||
clearMonetizationInfo();
|
||||
clearMonetizationVerificationError();
|
||||
});
|
||||
|
||||
const handleClose = useLastCallback(() => {
|
||||
closeMonetizationVerificationModal();
|
||||
});
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
hasCloseButton
|
||||
title={lang('EnterPassword')}
|
||||
title={lang('CheckPasswordTitle')}
|
||||
className={styles.root}
|
||||
contentClassName={styles.content}
|
||||
onClose={onClose}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<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')}
|
||||
placeholder={lang('CheckPasswordPlaceholder')}
|
||||
error={renderingModal?.errorKey && lang.withRegular(renderingModal.errorKey)}
|
||||
description={lang('CheckPasswordDescription')}
|
||||
clearError={handleClearError}
|
||||
isLoading={isLoading}
|
||||
isLoading={renderingModal?.isLoading}
|
||||
hint={passwordHint}
|
||||
isPasswordVisible={shouldShowPassword}
|
||||
shouldResetValue={isOpen}
|
||||
@ -84,4 +87,16 @@ const VerificationMonetizationModal: FC<OwnProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(VerificationMonetizationModal);
|
||||
export default memo(withGlobal(
|
||||
(global): StateProps => {
|
||||
const {
|
||||
twoFaSettings: {
|
||||
hint: passwordHint,
|
||||
},
|
||||
} = global;
|
||||
|
||||
return {
|
||||
passwordHint,
|
||||
};
|
||||
},
|
||||
)(VerificationMonetizationModal));
|
||||
|
||||
@ -6,6 +6,7 @@ import type { GlobalState } from '../../../../global/types';
|
||||
import type { TwoFaDispatch, TwoFaState } from '../../../../hooks/reducers/useTwoFaReducer';
|
||||
import { SettingsScreens } from '../../../../types';
|
||||
|
||||
import useLang from '../../../../hooks/useLang';
|
||||
import useOldLang from '../../../../hooks/useOldLang';
|
||||
|
||||
import SettingsTwoFaPassword from '../SettingsPasswordForm';
|
||||
@ -33,7 +34,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
||||
state,
|
||||
hint,
|
||||
isLoading,
|
||||
error,
|
||||
errorKey,
|
||||
waitingEmailCodeLength,
|
||||
dispatch,
|
||||
isActive,
|
||||
@ -49,6 +50,9 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
||||
clearPassword,
|
||||
} = getActions();
|
||||
|
||||
const lang = useLang();
|
||||
const oldLang = useOldLang();
|
||||
|
||||
useEffect(() => {
|
||||
if (waitingEmailCodeLength) {
|
||||
if (currentScreen === SettingsScreens.TwoFaNewPasswordEmail) {
|
||||
@ -153,8 +157,6 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
||||
provideTwoFaEmailCode({ code });
|
||||
}, [provideTwoFaEmailCode]);
|
||||
|
||||
const lang = useOldLang();
|
||||
|
||||
switch (currentScreen) {
|
||||
case SettingsScreens.TwoFaDisabled:
|
||||
return (
|
||||
@ -175,8 +177,8 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
||||
case SettingsScreens.TwoFaNewPassword:
|
||||
return (
|
||||
<SettingsTwoFaPassword
|
||||
placeholder={lang('PleaseEnterPassword')}
|
||||
submitLabel={lang('Continue')}
|
||||
placeholder={oldLang('PleaseEnterPassword')}
|
||||
submitLabel={oldLang('Continue')}
|
||||
onSubmit={handleNewPassword}
|
||||
isActive={isActive || [
|
||||
SettingsScreens.TwoFaNewPasswordConfirm,
|
||||
@ -193,8 +195,8 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
||||
return (
|
||||
<SettingsTwoFaPassword
|
||||
expectedPassword={state.password}
|
||||
placeholder={lang('PleaseReEnterPassword')}
|
||||
submitLabel={lang('Continue')}
|
||||
placeholder={oldLang('PleaseReEnterPassword')}
|
||||
submitLabel={oldLang('Continue')}
|
||||
onSubmit={handleNewPasswordConfirm}
|
||||
isActive={isActive || [
|
||||
SettingsScreens.TwoFaNewPasswordHint,
|
||||
@ -210,7 +212,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
||||
return (
|
||||
<SettingsTwoFaSkippableForm
|
||||
icon="hint"
|
||||
placeholder={lang('PasswordHintPlaceholder')}
|
||||
placeholder={oldLang('PasswordHintPlaceholder')}
|
||||
onSubmit={handleNewPasswordHint}
|
||||
isActive={isActive || [
|
||||
SettingsScreens.TwoFaNewPasswordEmail,
|
||||
@ -227,9 +229,9 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
||||
icon="email"
|
||||
type="email"
|
||||
isLoading={isLoading}
|
||||
error={error}
|
||||
error={errorKey && lang.withRegular(errorKey)}
|
||||
clearError={clearTwoFaError}
|
||||
placeholder={lang('RecoveryEmailTitle')}
|
||||
placeholder={oldLang('RecoveryEmailTitle')}
|
||||
shouldConfirm
|
||||
onSubmit={handleNewPasswordEmail}
|
||||
isActive={isActive || [
|
||||
@ -244,7 +246,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
||||
return (
|
||||
<SettingsTwoFaEmailCode
|
||||
isLoading={isLoading}
|
||||
error={error}
|
||||
error={errorKey && lang.withRegular(errorKey)}
|
||||
clearError={clearTwoFaError}
|
||||
onSubmit={handleEmailCode}
|
||||
isActive={isActive || shownScreen === SettingsScreens.TwoFaCongratulations}
|
||||
@ -284,7 +286,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
||||
return (
|
||||
<SettingsTwoFaPassword
|
||||
isLoading={isLoading}
|
||||
error={error}
|
||||
error={errorKey && lang.withRegular(errorKey)}
|
||||
clearError={clearTwoFaError}
|
||||
hint={hint}
|
||||
onSubmit={handleChangePasswordCurrent}
|
||||
@ -301,7 +303,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
||||
case SettingsScreens.TwoFaChangePasswordNew:
|
||||
return (
|
||||
<SettingsTwoFaPassword
|
||||
placeholder={lang('PleaseEnterNewFirstPassword')}
|
||||
placeholder={oldLang('PleaseEnterNewFirstPassword')}
|
||||
onSubmit={handleChangePasswordNew}
|
||||
isActive={isActive || [
|
||||
SettingsScreens.TwoFaChangePasswordConfirm,
|
||||
@ -316,7 +318,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
||||
return (
|
||||
<SettingsTwoFaPassword
|
||||
expectedPassword={state.password}
|
||||
placeholder={lang('PleaseReEnterPassword')}
|
||||
placeholder={oldLang('PleaseReEnterPassword')}
|
||||
onSubmit={handleChangePasswordConfirm}
|
||||
isActive={isActive || [
|
||||
SettingsScreens.TwoFaChangePasswordHint,
|
||||
@ -330,10 +332,10 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
||||
return (
|
||||
<SettingsTwoFaSkippableForm
|
||||
isLoading={isLoading}
|
||||
error={error}
|
||||
error={errorKey && lang.withRegular(errorKey)}
|
||||
clearError={clearTwoFaError}
|
||||
icon="hint"
|
||||
placeholder={lang('PasswordHintPlaceholder')}
|
||||
placeholder={oldLang('PasswordHintPlaceholder')}
|
||||
onSubmit={handleChangePasswordHint}
|
||||
isActive={isActive || shownScreen === SettingsScreens.TwoFaCongratulations}
|
||||
onReset={onReset}
|
||||
@ -344,7 +346,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
||||
return (
|
||||
<SettingsTwoFaPassword
|
||||
isLoading={isLoading}
|
||||
error={error}
|
||||
error={errorKey && lang.withRegular(errorKey)}
|
||||
clearError={clearTwoFaError}
|
||||
hint={hint}
|
||||
onSubmit={handleTurnOff}
|
||||
@ -357,7 +359,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
||||
return (
|
||||
<SettingsTwoFaPassword
|
||||
isLoading={isLoading}
|
||||
error={error}
|
||||
error={errorKey && lang.withRegular(errorKey)}
|
||||
clearError={clearTwoFaError}
|
||||
hint={hint}
|
||||
onSubmit={handleRecoveryEmailCurrentPassword}
|
||||
@ -375,7 +377,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
||||
<SettingsTwoFaSkippableForm
|
||||
icon="email"
|
||||
type="email"
|
||||
placeholder={lang('RecoveryEmailTitle')}
|
||||
placeholder={oldLang('RecoveryEmailTitle')}
|
||||
onSubmit={handleRecoveryEmail}
|
||||
isActive={isActive || [
|
||||
SettingsScreens.TwoFaRecoveryEmailCode,
|
||||
@ -389,7 +391,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
||||
return (
|
||||
<SettingsTwoFaEmailCode
|
||||
isLoading={isLoading}
|
||||
error={error}
|
||||
error={errorKey && lang.withRegular(errorKey)}
|
||||
clearError={clearTwoFaError}
|
||||
onSubmit={handleEmailCode}
|
||||
isActive={isActive || shownScreen === SettingsScreens.TwoFaCongratulations}
|
||||
|
||||
@ -245,6 +245,7 @@ const Main = ({
|
||||
loadAvailableEffects,
|
||||
loadTopBotApps,
|
||||
loadPaidReactionPrivacy,
|
||||
loadPasswordInfo,
|
||||
} = getActions();
|
||||
|
||||
if (DEBUG && !DEBUG_isLogged) {
|
||||
@ -333,6 +334,7 @@ const Main = ({
|
||||
loadAuthorizations();
|
||||
loadTopBotApps();
|
||||
loadPaidReactionPrivacy();
|
||||
loadPasswordInfo();
|
||||
}
|
||||
}, [isMasterTab, isSynced]);
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import type { TabState } from '../../global/types';
|
||||
import { selectTabState } from '../../global/selectors';
|
||||
import { pick } from '../../util/iteratees';
|
||||
|
||||
import VerificationMonetizationModal from '../common/VerificationMonetizationModal.async';
|
||||
import WebAppsCloseConfirmationModal from '../main/WebAppsCloseConfirmationModal.async';
|
||||
import AboutAdsModal from './aboutAds/AboutAdsModal.async';
|
||||
import AttachBotInstallModal from './attachBotInstall/AttachBotInstallModal.async';
|
||||
@ -14,6 +15,7 @@ import ChatInviteModal from './chatInvite/ChatInviteModal.async';
|
||||
import ChatlistModal from './chatlist/ChatlistModal.async';
|
||||
import CollectibleInfoModal from './collectible/CollectibleInfoModal.async';
|
||||
import EmojiStatusAccessModal from './emojiStatusAccess/EmojiStatusAccessModal.async';
|
||||
import GiftWithdrawModal from './gift/fragment/GiftWithdrawModal.async';
|
||||
import PremiumGiftModal from './gift/GiftModal.async';
|
||||
import GiftInfoModal from './gift/info/GiftInfoModal.async';
|
||||
import GiftRecipientPicker from './gift/recipient/GiftRecipientPicker.async';
|
||||
@ -65,7 +67,9 @@ type ModalKey = keyof Pick<TabState,
|
||||
'emojiStatusAccessModal' |
|
||||
'locationAccessModal' |
|
||||
'aboutAdsModal' |
|
||||
'giftUpgradeModal'
|
||||
'giftUpgradeModal' |
|
||||
'monetizationVerificationModal' |
|
||||
'giftWithdrawModal'
|
||||
>;
|
||||
|
||||
type StateProps = {
|
||||
@ -109,6 +113,8 @@ const MODALS: ModalRegistry = {
|
||||
locationAccessModal: LocationAccessModal,
|
||||
aboutAdsModal: AboutAdsModal,
|
||||
giftUpgradeModal: GiftUpgradeModal,
|
||||
monetizationVerificationModal: VerificationMonetizationModal,
|
||||
giftWithdrawModal: GiftWithdrawModal,
|
||||
};
|
||||
const MODAL_KEYS = Object.keys(MODALS) as ModalKey[];
|
||||
const MODAL_ENTRIES = Object.entries(MODALS) as Entries<ModalRegistry>;
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
import type { FC } from '../../../../lib/teact/teact';
|
||||
import React from '../../../../lib/teact/teact';
|
||||
|
||||
import type { OwnProps } from './GiftWithdrawModal';
|
||||
|
||||
import { Bundles } from '../../../../util/moduleLoader';
|
||||
|
||||
import useModuleLoader from '../../../../hooks/useModuleLoader';
|
||||
|
||||
const GiftWithdrawModalAsync: FC<OwnProps> = (props) => {
|
||||
const { modal } = props;
|
||||
const GiftWithdrawModal = useModuleLoader(Bundles.Stars, 'GiftWithdrawModal', !modal);
|
||||
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
return GiftWithdrawModal ? <GiftWithdrawModal {...props} /> : undefined;
|
||||
};
|
||||
|
||||
export default GiftWithdrawModalAsync;
|
||||
@ -0,0 +1,39 @@
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.giftPreview {
|
||||
width: 5.625rem;
|
||||
height: 5.625rem;
|
||||
position: relative;
|
||||
|
||||
display: grid;
|
||||
place-items: center;
|
||||
|
||||
overflow: hidden;
|
||||
border-radius: 0.625rem;
|
||||
}
|
||||
|
||||
.backdrop {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
}
|
||||
|
||||
.description {
|
||||
text-wrap: pretty;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
font-size: 3rem;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.noPassword {
|
||||
font-weight: var(--font-weight-semibold);
|
||||
}
|
||||
157
src/components/modals/gift/fragment/GiftWithdrawModal.tsx
Normal file
157
src/components/modals/gift/fragment/GiftWithdrawModal.tsx
Normal file
@ -0,0 +1,157 @@
|
||||
import React, {
|
||||
memo,
|
||||
useState,
|
||||
} from '../../../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../../../global';
|
||||
|
||||
import type { ApiStarGiftUnique } from '../../../../api/types';
|
||||
import type { TabState } from '../../../../global/types';
|
||||
import type { CustomPeer } from '../../../../types';
|
||||
|
||||
import { getDays } from '../../../../util/dates/units';
|
||||
import { getServerTime } from '../../../../util/serverTime';
|
||||
import { getGiftAttributes } from '../../../common/helpers/gifts';
|
||||
import { REM } from '../../../common/helpers/mediaDimensions';
|
||||
|
||||
import useCurrentOrPrev from '../../../../hooks/useCurrentOrPrev';
|
||||
import useLang from '../../../../hooks/useLang';
|
||||
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||
|
||||
import AnimatedIconFromSticker from '../../../common/AnimatedIconFromSticker';
|
||||
import Avatar from '../../../common/Avatar';
|
||||
import Icon from '../../../common/icons/Icon';
|
||||
import PasswordForm from '../../../common/PasswordForm';
|
||||
import RadialPatternBackground from '../../../common/profile/RadialPatternBackground';
|
||||
import Modal from '../../../ui/Modal';
|
||||
|
||||
import styles from './GiftWithdrawModal.module.scss';
|
||||
|
||||
export type OwnProps = {
|
||||
modal: TabState['giftWithdrawModal'];
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
hasPassword?: boolean;
|
||||
passwordHint?: string;
|
||||
};
|
||||
|
||||
const FRAGMENT_PEER: CustomPeer = {
|
||||
isCustomPeer: true,
|
||||
avatarIcon: 'fragment',
|
||||
title: '',
|
||||
customPeerAvatarColor: '#000000',
|
||||
};
|
||||
const GIFT_STICKER_SIZE = 4.5 * REM;
|
||||
|
||||
const GiftWithdrawModal = ({ modal, hasPassword, passwordHint }: OwnProps & StateProps) => {
|
||||
const { closeGiftWithdrawModal, clearGiftWithdrawError, processStarGiftWithdrawal } = getActions();
|
||||
const isOpen = Boolean(modal);
|
||||
|
||||
const [shouldShowPassword, setShouldShowPassword] = useState(false);
|
||||
|
||||
const lang = useLang();
|
||||
|
||||
const renderingModal = useCurrentOrPrev(modal);
|
||||
const gift = renderingModal?.gift?.gift as ApiStarGiftUnique;
|
||||
const giftAttributes = gift && getGiftAttributes(gift);
|
||||
const exportDelay = renderingModal?.gift?.canExportAt
|
||||
? Math.max(renderingModal.gift.canExportAt - getServerTime(), 0) : undefined;
|
||||
|
||||
const handleClose = useLastCallback(() => {
|
||||
closeGiftWithdrawModal();
|
||||
});
|
||||
|
||||
const handleSubmit = useLastCallback((password: string) => {
|
||||
processStarGiftWithdrawal({
|
||||
gift: renderingModal!.gift.inputGift!,
|
||||
password,
|
||||
});
|
||||
});
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
title={lang('GiftWithdrawTitle')}
|
||||
hasCloseButton
|
||||
isSlim
|
||||
onClose={handleClose}
|
||||
>
|
||||
{giftAttributes && (
|
||||
<>
|
||||
<div className={styles.header}>
|
||||
<div className={styles.giftPreview}>
|
||||
<RadialPatternBackground
|
||||
className={styles.backdrop}
|
||||
backgroundColors={[giftAttributes.backdrop!.centerColor, giftAttributes.backdrop!.edgeColor]}
|
||||
patternColor={giftAttributes.backdrop?.patternColor}
|
||||
patternIcon={giftAttributes.pattern?.sticker}
|
||||
/>
|
||||
<AnimatedIconFromSticker
|
||||
className={styles.sticker}
|
||||
size={GIFT_STICKER_SIZE}
|
||||
sticker={giftAttributes.model?.sticker}
|
||||
/>
|
||||
</div>
|
||||
<Icon name="next" className={styles.arrow} />
|
||||
<Avatar
|
||||
peer={FRAGMENT_PEER}
|
||||
size="giant"
|
||||
className={styles.avatar}
|
||||
/>
|
||||
</div>
|
||||
<p className={styles.description}>
|
||||
{lang('GiftWithdrawDescription', {
|
||||
gift: `${gift.title} #${gift.number}`,
|
||||
}, {
|
||||
withNodes: true,
|
||||
withMarkdown: true,
|
||||
renderTextFilters: ['br'],
|
||||
})}
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
{Boolean(exportDelay) && (
|
||||
<p className={styles.exportHint}>
|
||||
{lang('GiftWithdrawWait', { days: getDays(exportDelay) }, { pluralValue: getDays(exportDelay) })}
|
||||
</p>
|
||||
)}
|
||||
{!hasPassword && <span className={styles.noPassword}>{lang('ErrorPasswordMissing')}</span>}
|
||||
{hasPassword && !exportDelay && (
|
||||
<PasswordForm
|
||||
shouldShowSubmit
|
||||
placeholder={lang('CheckPasswordPlaceholder')}
|
||||
error={renderingModal?.errorKey && lang.withRegular(renderingModal?.errorKey)}
|
||||
description={lang('CheckPasswordDescription')}
|
||||
clearError={clearGiftWithdrawError}
|
||||
isLoading={renderingModal?.isLoading}
|
||||
hint={passwordHint}
|
||||
isPasswordVisible={shouldShowPassword}
|
||||
shouldResetValue={isOpen}
|
||||
onChangePasswordVisibility={setShouldShowPassword}
|
||||
submitLabel={lang('GiftWithdrawSubmit')}
|
||||
onSubmit={handleSubmit}
|
||||
/>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(withGlobal<OwnProps>(
|
||||
(global): StateProps => {
|
||||
const {
|
||||
settings: {
|
||||
byKey: {
|
||||
hasPassword,
|
||||
},
|
||||
},
|
||||
twoFaSettings: {
|
||||
hint: passwordHint,
|
||||
},
|
||||
} = global;
|
||||
|
||||
return {
|
||||
hasPassword,
|
||||
passwordHint,
|
||||
};
|
||||
},
|
||||
)(GiftWithdrawModal));
|
||||
@ -72,6 +72,7 @@ const GiftInfoModal = ({
|
||||
openGiftUpgradeModal,
|
||||
showNotification,
|
||||
openChatWithDraft,
|
||||
openGiftWithdrawModal,
|
||||
} = getActions();
|
||||
|
||||
const [isConvertConfirmOpen, openConvertConfirm, closeConvertConfirm] = useFlag();
|
||||
@ -127,6 +128,11 @@ const GiftInfoModal = ({
|
||||
handleClose();
|
||||
});
|
||||
|
||||
const handleWithdraw = useLastCallback(() => {
|
||||
if (savedGift?.gift.type !== 'starGiftUnique') return;
|
||||
openGiftWithdrawModal({ gift: savedGift });
|
||||
});
|
||||
|
||||
const handleFocusUpgraded = useLastCallback(() => {
|
||||
if (!savedGift?.upgradeMsgId || !renderingTargetPeer) return;
|
||||
const { upgradeMsgId } = savedGift;
|
||||
@ -291,6 +297,11 @@ const GiftInfoModal = ({
|
||||
>
|
||||
{lang('Share')}
|
||||
</MenuItem>
|
||||
{canUpdate && isUniqueGift && (
|
||||
<MenuItem icon="diamond" onClick={handleWithdraw}>
|
||||
{lang('GiftInfoWithdraw')}
|
||||
</MenuItem>
|
||||
)}
|
||||
</DropdownMenu>
|
||||
);
|
||||
|
||||
|
||||
@ -4,9 +4,11 @@ import { getActions, withGlobal } from '../../global';
|
||||
|
||||
import type { ApiPaymentCredentials } from '../../api/types';
|
||||
import type { FormState } from '../../hooks/reducers/usePaymentReducer';
|
||||
import type { RegularLangFnParameters } from '../../util/localization';
|
||||
|
||||
import { selectTabState } from '../../global/selectors';
|
||||
|
||||
import useLang from '../../hooks/useLang';
|
||||
import useOldLang from '../../hooks/useOldLang';
|
||||
|
||||
import PasswordForm from '../common/PasswordForm';
|
||||
@ -20,14 +22,14 @@ interface OwnProps {
|
||||
}
|
||||
|
||||
interface StateProps {
|
||||
error?: string;
|
||||
errorKey?: RegularLangFnParameters;
|
||||
passwordHint?: string;
|
||||
savedCredentials?: ApiPaymentCredentials[];
|
||||
}
|
||||
|
||||
const PasswordConfirm: FC<OwnProps & StateProps> = ({
|
||||
isActive,
|
||||
error,
|
||||
errorKey,
|
||||
state,
|
||||
savedCredentials,
|
||||
passwordHint,
|
||||
@ -35,7 +37,9 @@ const PasswordConfirm: FC<OwnProps & StateProps> = ({
|
||||
}) => {
|
||||
const { clearPaymentError } = getActions();
|
||||
|
||||
const lang = useOldLang();
|
||||
const oldLang = useOldLang();
|
||||
const lang = useLang();
|
||||
|
||||
const [shouldShowPassword, setShouldShowPassword] = useState(false);
|
||||
const cardName = useMemo(() => {
|
||||
return savedCredentials?.length && state.savedCredentialId
|
||||
@ -48,10 +52,10 @@ const PasswordConfirm: FC<OwnProps & StateProps> = ({
|
||||
<PasswordMonkey isBig isPasswordVisible={shouldShowPassword} />
|
||||
|
||||
<PasswordForm
|
||||
error={error ? lang(error) : undefined}
|
||||
error={errorKey && lang.withRegular(errorKey)}
|
||||
hint={passwordHint}
|
||||
description={lang('PaymentConfirmationMessage', cardName)}
|
||||
placeholder={lang('Password')}
|
||||
description={oldLang('PaymentConfirmationMessage', cardName)}
|
||||
placeholder={oldLang('Password')}
|
||||
clearError={clearPaymentError}
|
||||
shouldShowSubmit={false}
|
||||
shouldResetValue={isActive}
|
||||
@ -66,7 +70,7 @@ const PasswordConfirm: FC<OwnProps & StateProps> = ({
|
||||
export default memo(withGlobal<OwnProps>((global): StateProps => {
|
||||
const { payment } = selectTabState(global);
|
||||
return {
|
||||
error: payment.error?.message,
|
||||
errorKey: payment.error?.messageKey,
|
||||
passwordHint: global.twoFaSettings.hint,
|
||||
savedCredentials: payment.form?.type === 'regular' ? payment.form.savedCredentials : undefined,
|
||||
};
|
||||
|
||||
@ -7,6 +7,7 @@ import React, {
|
||||
import type { ApiCountry } from '../../api/types';
|
||||
import type { FormEditDispatch, FormState } from '../../hooks/reducers/usePaymentReducer';
|
||||
|
||||
import useLang from '../../hooks/useLang';
|
||||
import useOldLang from '../../hooks/useOldLang';
|
||||
|
||||
import Checkbox from '../ui/Checkbox';
|
||||
@ -75,58 +76,59 @@ const PaymentInfo: FC<OwnProps> = ({
|
||||
dispatch({ type: 'changeSaveCredentials', payload: e.target.value });
|
||||
}, [dispatch]);
|
||||
|
||||
const lang = useOldLang();
|
||||
const oldLang = useOldLang();
|
||||
const lang = useLang();
|
||||
|
||||
const { formErrors = {} } = state;
|
||||
|
||||
return (
|
||||
<div className="PaymentInfo">
|
||||
<form>
|
||||
<h5>{lang('PaymentCardTitle')}</h5>
|
||||
<h5>{oldLang('PaymentCardTitle')}</h5>
|
||||
<CardInput
|
||||
onChange={handleCardNumberChange}
|
||||
value={state.cardNumber}
|
||||
error={formErrors.cardNumber}
|
||||
error={formErrors.cardNumber && lang.withRegular(formErrors.cardNumber)}
|
||||
/>
|
||||
{needCardholderName && (
|
||||
<InputText
|
||||
label={lang('Checkout.NewCard.CardholderNamePlaceholder')}
|
||||
label={oldLang('Checkout.NewCard.CardholderNamePlaceholder')}
|
||||
onChange={handleCardholderChange}
|
||||
value={state.cardholder}
|
||||
inputMode="text"
|
||||
tabIndex={0}
|
||||
error={formErrors.cardholder}
|
||||
error={formErrors.cardholder && lang.withRegular(formErrors.cardholder)}
|
||||
/>
|
||||
)}
|
||||
<section className="inline-inputs">
|
||||
<ExpiryInput
|
||||
value={state.expiry}
|
||||
onChange={handleExpiryChange}
|
||||
error={formErrors.expiry}
|
||||
error={formErrors.expiry && lang.withRegular(formErrors.expiry)}
|
||||
/>
|
||||
<InputText
|
||||
label={lang('lng_payments_card_cvc')}
|
||||
label={oldLang('lng_payments_card_cvc')}
|
||||
onChange={handleCvvChange}
|
||||
value={state.cvv}
|
||||
inputMode="numeric"
|
||||
maxLength={3}
|
||||
tabIndex={0}
|
||||
error={formErrors.cvv}
|
||||
error={formErrors.cvv && lang.withRegular(formErrors.cvv)}
|
||||
teactExperimentControlled
|
||||
/>
|
||||
</section>
|
||||
{needCountry || needZip ? (
|
||||
<h5>{lang('PaymentBillingAddress')}</h5>
|
||||
<h5>{oldLang('PaymentBillingAddress')}</h5>
|
||||
) : undefined}
|
||||
<section className="inline-inputs">
|
||||
{needCountry && (
|
||||
<Select
|
||||
label={lang('PaymentShippingCountry')}
|
||||
label={oldLang('PaymentShippingCountry')}
|
||||
onChange={handleCountryChange}
|
||||
value={state.billingCountry}
|
||||
hasArrow={Boolean(true)}
|
||||
id="billing-country"
|
||||
error={formErrors.billingCountry}
|
||||
error={formErrors.billingCountry && lang.withRegular(formErrors.billingCountry)}
|
||||
tabIndex={0}
|
||||
ref={selectCountryRef}
|
||||
>
|
||||
@ -145,22 +147,22 @@ const PaymentInfo: FC<OwnProps> = ({
|
||||
)}
|
||||
{needZip && (
|
||||
<InputText
|
||||
label={lang('PaymentShippingZipPlaceholder')}
|
||||
label={oldLang('PaymentShippingZipPlaceholder')}
|
||||
onChange={handleBillingPostCodeChange}
|
||||
value={state.billingZip}
|
||||
inputMode="text"
|
||||
tabIndex={0}
|
||||
maxLength={12}
|
||||
error={formErrors.billingZip}
|
||||
error={formErrors.billingZip && lang.withRegular(formErrors.billingZip)}
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
<div className="checkbox">
|
||||
<Checkbox
|
||||
label={lang('PaymentCardSavePaymentInformation')}
|
||||
label={oldLang('PaymentCardSavePaymentInformation')}
|
||||
checked={canSaveCredentials ? state.saveCredentials : false}
|
||||
tabIndex={0}
|
||||
subLabel={lang(canSaveCredentials ? 'Checkout.NewCard.SaveInfoHelp' : 'Checkout.2FA.Text')}
|
||||
subLabel={oldLang(canSaveCredentials ? 'Checkout.NewCard.SaveInfoHelp' : 'Checkout.2FA.Text')}
|
||||
onChange={handleChangeSaveCredentials}
|
||||
disabled={!canSaveCredentials}
|
||||
/>
|
||||
|
||||
@ -171,7 +171,7 @@ const PaymentModal: FC<OwnProps & StateProps> = ({
|
||||
paymentDispatch({
|
||||
type: 'setFormErrors',
|
||||
payload: {
|
||||
[error.field]: error.message,
|
||||
[error.field]: error.messageKey,
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -250,8 +250,7 @@ const PaymentModal: FC<OwnProps & StateProps> = ({
|
||||
isOpen={Boolean(error)}
|
||||
onClose={handleErrorModalClose}
|
||||
>
|
||||
<h4>{error.description || 'Error'}</h4>
|
||||
<p>{error.description || 'Error'}</p>
|
||||
<h4>{error.descriptionKey ? lang.withRegular(error.descriptionKey) : lang('ErrorUnspecified')}</h4>
|
||||
<div className="dialog-buttons mt-2">
|
||||
<Button
|
||||
isText
|
||||
|
||||
@ -8,6 +8,7 @@ import type { ApiCountry } from '../../api/types';
|
||||
import type { FormEditDispatch, FormState } from '../../hooks/reducers/usePaymentReducer';
|
||||
|
||||
import useFocusAfterAnimation from '../../hooks/useFocusAfterAnimation';
|
||||
import useLang from '../../hooks/useLang';
|
||||
import useOldLang from '../../hooks/useOldLang';
|
||||
|
||||
import Checkbox from '../ui/Checkbox';
|
||||
@ -49,7 +50,8 @@ const ShippingInfo: FC<OwnProps> = ({
|
||||
}
|
||||
}, [state.countryIso2]);
|
||||
|
||||
const lang = useOldLang();
|
||||
const oldLang = useOldLang();
|
||||
const lang = useLang();
|
||||
|
||||
useFocusAfterAnimation(inputRef);
|
||||
|
||||
@ -104,46 +106,46 @@ const ShippingInfo: FC<OwnProps> = ({
|
||||
<form>
|
||||
{needAddress ? (
|
||||
<div>
|
||||
<h5>{lang('PaymentShippingAddress')}</h5>
|
||||
<h5>{oldLang('PaymentShippingAddress')}</h5>
|
||||
<InputText
|
||||
ref={inputRef}
|
||||
label={lang('PaymentShippingAddress1Placeholder')}
|
||||
label={oldLang('PaymentShippingAddress1Placeholder')}
|
||||
onChange={handleAddress1Change}
|
||||
value={state.streetLine1}
|
||||
inputMode="text"
|
||||
tabIndex={0}
|
||||
error={formErrors.streetLine1}
|
||||
error={formErrors.streetLine1 && lang.withRegular(formErrors.streetLine1)}
|
||||
/>
|
||||
<InputText
|
||||
label={lang('PaymentShippingAddress2Placeholder')}
|
||||
label={oldLang('PaymentShippingAddress2Placeholder')}
|
||||
onChange={handleAddress2Change}
|
||||
value={state.streetLine2}
|
||||
inputMode="text"
|
||||
tabIndex={0}
|
||||
error={formErrors.streetLine2}
|
||||
error={formErrors.streetLine2 && lang.withRegular(formErrors.streetLine2)}
|
||||
/>
|
||||
<InputText
|
||||
label={lang('PaymentShippingCityPlaceholder')}
|
||||
label={oldLang('PaymentShippingCityPlaceholder')}
|
||||
onChange={handleCityChange}
|
||||
value={state.city}
|
||||
inputMode="text"
|
||||
tabIndex={0}
|
||||
error={formErrors.city}
|
||||
error={formErrors.city && lang.withRegular(formErrors.city)}
|
||||
/>
|
||||
<InputText
|
||||
label={lang('PaymentShippingStatePlaceholder')}
|
||||
label={oldLang('PaymentShippingStatePlaceholder')}
|
||||
onChange={handleStateChange}
|
||||
value={state.state}
|
||||
inputMode="text"
|
||||
error={formErrors.state}
|
||||
error={formErrors.state && lang.withRegular(formErrors.state)}
|
||||
/>
|
||||
<Select
|
||||
label={lang('PaymentShippingCountry')}
|
||||
label={oldLang('PaymentShippingCountry')}
|
||||
onChange={handleCountryChange}
|
||||
value={state.countryIso2}
|
||||
hasArrow={Boolean(true)}
|
||||
id="shipping-country"
|
||||
error={formErrors.countryIso2}
|
||||
error={formErrors.countryIso2 && lang.withRegular(formErrors.countryIso2)}
|
||||
ref={selectCountryRef}
|
||||
tabIndex={0}
|
||||
>
|
||||
@ -159,52 +161,52 @@ const ShippingInfo: FC<OwnProps> = ({
|
||||
</Select>
|
||||
|
||||
<InputText
|
||||
label={lang('PaymentShippingZipPlaceholder')}
|
||||
label={oldLang('PaymentShippingZipPlaceholder')}
|
||||
onChange={handlePostCodeChange}
|
||||
value={state.postCode}
|
||||
inputMode="text"
|
||||
tabIndex={0}
|
||||
error={formErrors.postCode}
|
||||
error={formErrors.postCode && lang.withRegular(formErrors.postCode)}
|
||||
/>
|
||||
</div>
|
||||
) : undefined}
|
||||
{ needName || needEmail || needPhone ? (
|
||||
<h5>{lang('PaymentShippingReceiver')}</h5>
|
||||
<h5>{oldLang('PaymentShippingReceiver')}</h5>
|
||||
) : undefined }
|
||||
{ needName && (
|
||||
<InputText
|
||||
label={lang('PaymentShippingName')}
|
||||
label={oldLang('PaymentShippingName')}
|
||||
onChange={handleFullNameChange}
|
||||
value={state.fullName}
|
||||
inputMode="text"
|
||||
tabIndex={0}
|
||||
error={formErrors.fullName}
|
||||
error={formErrors.fullName && lang.withRegular(formErrors.fullName)}
|
||||
/>
|
||||
) }
|
||||
{ needEmail && (
|
||||
<InputText
|
||||
label={lang('PaymentShippingEmailPlaceholder')}
|
||||
label={oldLang('PaymentShippingEmailPlaceholder')}
|
||||
onChange={handleEmailChange}
|
||||
value={state.email}
|
||||
inputMode="email"
|
||||
tabIndex={0}
|
||||
error={formErrors.email}
|
||||
error={formErrors.email && lang.withRegular(formErrors.email)}
|
||||
/>
|
||||
) }
|
||||
{ needPhone && (
|
||||
<InputText
|
||||
label={lang('PaymentShippingPhoneNumber')}
|
||||
label={oldLang('PaymentShippingPhoneNumber')}
|
||||
onChange={handlePhoneChange}
|
||||
value={state.phone}
|
||||
inputMode="tel"
|
||||
tabIndex={0}
|
||||
error={formErrors.phone}
|
||||
error={formErrors.phone && lang.withRegular(formErrors.phone)}
|
||||
ref={phoneRef}
|
||||
/>
|
||||
) }
|
||||
<Checkbox
|
||||
label={lang('PaymentShippingSave')}
|
||||
subLabel={lang('PaymentShippingSaveInfo')}
|
||||
label={oldLang('PaymentShippingSave')}
|
||||
subLabel={oldLang('PaymentShippingSaveInfo')}
|
||||
checked={Boolean(state.saveInfo)}
|
||||
tabIndex={0}
|
||||
onChange={handleSaveInfoChange}
|
||||
|
||||
@ -18,7 +18,6 @@ import useOldLang from '../../../hooks/useOldLang';
|
||||
import AboutMonetizationModal from '../../common/AboutMonetizationModal.async';
|
||||
import Icon from '../../common/icons/Icon';
|
||||
import SafeLink from '../../common/SafeLink';
|
||||
import VerificationMonetizationModal from '../../common/VerificationMonetizationModal.async';
|
||||
import Button from '../../ui/Button';
|
||||
import ConfirmDialog from '../../ui/ConfirmDialog';
|
||||
import Link from '../../ui/Link';
|
||||
@ -53,9 +52,6 @@ type StateProps = {
|
||||
isCreator?: boolean;
|
||||
isChannelRevenueWithdrawalEnabled?: boolean;
|
||||
hasPassword?: boolean;
|
||||
passwordHint?: string;
|
||||
error?: string;
|
||||
isLoading?: boolean;
|
||||
};
|
||||
|
||||
const MonetizationStatistics = ({
|
||||
@ -65,11 +61,8 @@ const MonetizationStatistics = ({
|
||||
isCreator,
|
||||
isChannelRevenueWithdrawalEnabled,
|
||||
hasPassword,
|
||||
passwordHint,
|
||||
error,
|
||||
isLoading,
|
||||
}: StateProps) => {
|
||||
const { loadChannelMonetizationStatistics, loadPasswordInfo } = getActions();
|
||||
const { loadChannelMonetizationStatistics, openMonetizationVerificationModal, loadPasswordInfo } = getActions();
|
||||
const oldLang = useOldLang();
|
||||
const lang = useLang();
|
||||
|
||||
@ -79,9 +72,6 @@ const MonetizationStatistics = ({
|
||||
const loadedCharts = useRef<string[]>([]);
|
||||
const forceUpdate = useForceUpdate();
|
||||
const [isAboutMonetizationModalOpen, openAboutMonetizationModal, closeAboutMonetizationModal] = useFlag(false);
|
||||
const [
|
||||
isVerificationMonetizationModalOpen, openVerificationMonetizationModal, closeVerificationMonetizationModal,
|
||||
] = useFlag(false);
|
||||
const [isConfirmPasswordDialogOpen, openConfirmPasswordDialogOpen, closeConfirmPasswordDialogOpen] = useFlag();
|
||||
const availableBalance = statistics?.balances?.availableBalance;
|
||||
const isWithdrawalEnabled = statistics?.balances?.isWithdrawalEnabled;
|
||||
@ -206,7 +196,9 @@ const MonetizationStatistics = ({
|
||||
|
||||
const verificationMonetizationHandler = useLastCallback(() => {
|
||||
if (hasPassword) {
|
||||
openVerificationMonetizationModal();
|
||||
openMonetizationVerificationModal({
|
||||
chatId,
|
||||
});
|
||||
} else {
|
||||
openConfirmPasswordDialogOpen();
|
||||
}
|
||||
@ -259,14 +251,6 @@ const MonetizationStatistics = ({
|
||||
isOpen={isAboutMonetizationModalOpen}
|
||||
onClose={closeAboutMonetizationModal}
|
||||
/>
|
||||
<VerificationMonetizationModal
|
||||
chatId={chatId}
|
||||
isOpen={isVerificationMonetizationModalOpen}
|
||||
onClose={closeVerificationMonetizationModal}
|
||||
passwordHint={passwordHint}
|
||||
error={error}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
<ConfirmDialog
|
||||
isOnlyConfirm
|
||||
isOpen={isConfirmPasswordDialogOpen}
|
||||
@ -289,12 +273,7 @@ export default memo(withGlobal(
|
||||
hasPassword,
|
||||
},
|
||||
},
|
||||
twoFaSettings: {
|
||||
hint: passwordHint,
|
||||
},
|
||||
} = global;
|
||||
const isLoading = global.monetizationInfo?.isLoading;
|
||||
const error = global.monetizationInfo?.error;
|
||||
const monetizationStatistics = tabState.monetizationStatistics;
|
||||
const chatId = monetizationStatistics && monetizationStatistics.chatId;
|
||||
const chat = chatId ? selectChat(global, chatId) : undefined;
|
||||
@ -312,9 +291,6 @@ export default memo(withGlobal(
|
||||
isCreator,
|
||||
isChannelRevenueWithdrawalEnabled,
|
||||
hasPassword,
|
||||
passwordHint,
|
||||
error,
|
||||
isLoading,
|
||||
};
|
||||
},
|
||||
)(MonetizationStatistics));
|
||||
|
||||
@ -11,6 +11,7 @@ import type { IconName } from '../../types/icons';
|
||||
import { getPeerTitle, getUserFullName } from '../../global/helpers';
|
||||
import { selectPeerStory, selectTabState } from '../../global/selectors';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
import { getHours } from '../../util/dates/units';
|
||||
import stopEvent from '../../util/stopEvent';
|
||||
|
||||
import useFlag from '../../hooks/useFlag';
|
||||
@ -299,7 +300,7 @@ function StorySettings({
|
||||
}
|
||||
|
||||
function renderPrivacyList() {
|
||||
const storyLifeTime = story ? convertSecondsToHours(story.expireDate - story.date) : 0;
|
||||
const storyLifeTime = story ? getHours(story.expireDate - story.date) : 0;
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -419,15 +420,3 @@ export default memo(withGlobal<OwnProps>((global): StateProps => {
|
||||
currentUserId: global.currentUserId!,
|
||||
};
|
||||
})(StorySettings));
|
||||
|
||||
function convertSecondsToHours(seconds: number): number {
|
||||
const secondsInHour = 3600;
|
||||
const minutesInHour = 60;
|
||||
|
||||
const hours = Math.floor(seconds / secondsInHour);
|
||||
const remainingSeconds = seconds % secondsInHour;
|
||||
const remainingMinutes = Math.floor(remainingSeconds / minutesInHour);
|
||||
|
||||
// If remaining minutes are greater than or equal to 30, round up the hours
|
||||
return remainingMinutes >= 30 ? hours + 1 : hours;
|
||||
}
|
||||
|
||||
@ -33,6 +33,7 @@ import './ui/passcode';
|
||||
import './ui/stars';
|
||||
import './ui/reactions';
|
||||
import './ui/stories';
|
||||
import './ui/statistics';
|
||||
import './apiUpdaters/initial';
|
||||
import './apiUpdaters/chats';
|
||||
import './apiUpdaters/messages';
|
||||
@ -41,6 +42,5 @@ import './apiUpdaters/symbols';
|
||||
import './apiUpdaters/misc';
|
||||
import './apiUpdaters/settings';
|
||||
import './apiUpdaters/twoFaSettings';
|
||||
import './apiUpdaters/password';
|
||||
import './apiUpdaters/calls';
|
||||
import './apiUpdaters/payments';
|
||||
|
||||
@ -2,6 +2,7 @@ import type {
|
||||
ApiInputInvoice, ApiInputInvoiceStarGift, ApiInputInvoiceStarGiftUpgrade, ApiRequestInputInvoice,
|
||||
} from '../../../api/types';
|
||||
import type { ApiCredentials } from '../../../components/payment/PaymentModal';
|
||||
import type { RegularLangFnParameters } from '../../../util/localization';
|
||||
import type {
|
||||
ActionReturnType, GlobalState, TabArgs,
|
||||
} from '../../types';
|
||||
@ -397,7 +398,7 @@ async function sendSmartGlocalCredentials<T extends GlobalState>(
|
||||
|
||||
if (result.status !== 'ok') {
|
||||
// TODO после получения документации сделать аналог getStripeError(result.error);
|
||||
const error = { description: 'payment error' };
|
||||
const error = { descriptionKey: { key: 'ErrorUnexpected' } satisfies RegularLangFnParameters };
|
||||
global = getGlobal();
|
||||
global = updateTabState(global, {
|
||||
payment: {
|
||||
@ -554,9 +555,9 @@ addActionHandler('validatePaymentPassword', async (global, actions, payload): Pr
|
||||
global = getGlobal();
|
||||
|
||||
if (!result) {
|
||||
global = updatePayment(global, { error: { message: 'Unknown Error', field: 'password' } }, tabId);
|
||||
global = updatePayment(global, { error: { messageKey: { key: 'ErrorUnexpected' }, field: 'password' } }, tabId);
|
||||
} else if ('error' in result) {
|
||||
global = updatePayment(global, { error: { message: result.error, field: 'password' } }, tabId);
|
||||
global = updatePayment(global, { error: { messageKey: result.messageKey, field: 'password' } }, tabId);
|
||||
} else {
|
||||
global = updatePayment(global, { temporaryPassword: result, step: PaymentStep.Checkout }, tabId);
|
||||
}
|
||||
@ -1063,3 +1064,51 @@ addActionHandler('openUniqueGiftBySlug', async (global, actions, payload): Promi
|
||||
|
||||
actions.openGiftInfoModal({ gift, tabId });
|
||||
});
|
||||
|
||||
addActionHandler('processStarGiftWithdrawal', async (global, actions, payload): Promise<void> => {
|
||||
const {
|
||||
gift, password, tabId = getCurrentTabId(),
|
||||
} = payload;
|
||||
|
||||
let giftWithdrawModal = selectTabState(global, tabId).giftWithdrawModal;
|
||||
if (!giftWithdrawModal) return;
|
||||
|
||||
global = updateTabState(global, {
|
||||
giftWithdrawModal: {
|
||||
...giftWithdrawModal,
|
||||
isLoading: true,
|
||||
errorKey: undefined,
|
||||
},
|
||||
}, tabId);
|
||||
setGlobal(global);
|
||||
|
||||
const inputGift = getRequestInputSavedStarGift(global, gift);
|
||||
if (!inputGift) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await callApi('fetchStarGiftWithdrawalUrl', { inputGift, password });
|
||||
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
global = getGlobal();
|
||||
giftWithdrawModal = selectTabState(global, tabId).giftWithdrawModal;
|
||||
if (!giftWithdrawModal) return;
|
||||
|
||||
if ('error' in result) {
|
||||
global = updateTabState(global, {
|
||||
giftWithdrawModal: {
|
||||
...giftWithdrawModal,
|
||||
isLoading: false,
|
||||
errorKey: result.messageKey,
|
||||
},
|
||||
}, tabId);
|
||||
setGlobal(global);
|
||||
return;
|
||||
}
|
||||
|
||||
actions.openUrl({ url: result.url, shouldSkipModal: true, tabId });
|
||||
actions.closeGiftWithdrawModal({ tabId });
|
||||
});
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import type { ActionReturnType } from '../../types';
|
||||
|
||||
import { areDeepEqual } from '../../../util/areDeepEqual';
|
||||
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
||||
import { callApi } from '../../../api/gramjs';
|
||||
@ -7,10 +5,10 @@ import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
||||
import {
|
||||
updateChannelMonetizationStatistics,
|
||||
updateMessageStatistics,
|
||||
updateMonetizationInfo,
|
||||
updateStatistics,
|
||||
updateStatisticsGraph,
|
||||
updateStoryStatistics,
|
||||
updateVerifyMonetizationModal,
|
||||
} from '../../reducers';
|
||||
import {
|
||||
selectChat,
|
||||
@ -229,12 +227,14 @@ addActionHandler('loadStoryPublicForwards', async (global, actions, payload): Pr
|
||||
setGlobal(global);
|
||||
});
|
||||
|
||||
addActionHandler('loadMonetizationRevenueWithdrawalUrl', async (global, actions, payload): Promise<void> => {
|
||||
addActionHandler('processMonetizationRevenueWithdrawalUrl', async (global, actions, payload): Promise<void> => {
|
||||
const {
|
||||
peerId, currentPassword, onSuccess, tabId = getCurrentTabId(),
|
||||
peerId, currentPassword, tabId = getCurrentTabId(),
|
||||
} = payload;
|
||||
|
||||
global = updateMonetizationInfo(global, { isLoading: true, error: undefined });
|
||||
global = updateVerifyMonetizationModal(global, {
|
||||
isLoading: true,
|
||||
}, tabId);
|
||||
setGlobal(global);
|
||||
|
||||
const peer = selectPeer(global, peerId);
|
||||
@ -242,27 +242,26 @@ addActionHandler('loadMonetizationRevenueWithdrawalUrl', async (global, actions,
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await callApi('loadMonetizationRevenueWithdrawalUrl', { peer, currentPassword });
|
||||
const result = await callApi('fetchMonetizationRevenueWithdrawalUrl', { peer, currentPassword });
|
||||
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
global = getGlobal();
|
||||
global = updateMonetizationInfo(global, { isLoading: false });
|
||||
global = updateVerifyMonetizationModal(global, {
|
||||
isLoading: false,
|
||||
errorKey: 'error' in result ? result.messageKey : undefined,
|
||||
}, tabId);
|
||||
setGlobal(global);
|
||||
|
||||
if (result) {
|
||||
onSuccess();
|
||||
if ('url' in result) {
|
||||
actions.openUrl({
|
||||
url: result.url,
|
||||
shouldSkipModal: true,
|
||||
tabId,
|
||||
ignoreDeepLinks: true,
|
||||
});
|
||||
actions.closeMonetizationVerificationModal({ tabId });
|
||||
}
|
||||
});
|
||||
|
||||
addActionHandler('clearMonetizationInfo', (global): ActionReturnType => {
|
||||
return updateMonetizationInfo(global, { error: undefined });
|
||||
});
|
||||
|
||||
@ -19,7 +19,7 @@ addActionHandler('loadPasswordInfo', async (global): Promise<void> => {
|
||||
addActionHandler('checkPassword', async (global, actions, payload): Promise<void> => {
|
||||
const { currentPassword, onSuccess } = payload;
|
||||
|
||||
global = updateTwoFaSettings(global, { isLoading: true, error: undefined });
|
||||
global = updateTwoFaSettings(global, { isLoading: true, errorKey: undefined });
|
||||
setGlobal(global);
|
||||
|
||||
const isSuccess = await callApi('checkPassword', currentPassword);
|
||||
@ -36,7 +36,7 @@ addActionHandler('checkPassword', async (global, actions, payload): Promise<void
|
||||
addActionHandler('clearPassword', async (global, actions, payload): Promise<void> => {
|
||||
const { currentPassword, onSuccess } = payload;
|
||||
|
||||
global = updateTwoFaSettings(global, { isLoading: true, error: undefined });
|
||||
global = updateTwoFaSettings(global, { isLoading: true, errorKey: undefined });
|
||||
setGlobal(global);
|
||||
|
||||
const isSuccess = await callApi('clearPassword', currentPassword);
|
||||
@ -55,7 +55,7 @@ addActionHandler('updatePassword', async (global, actions, payload): Promise<voi
|
||||
currentPassword, password, hint, email, onSuccess,
|
||||
} = payload;
|
||||
|
||||
global = updateTwoFaSettings(global, { isLoading: true, error: undefined });
|
||||
global = updateTwoFaSettings(global, { isLoading: true, errorKey: undefined });
|
||||
setGlobal(global);
|
||||
|
||||
const isSuccess = await callApi('updatePassword', currentPassword, password, hint, email);
|
||||
@ -74,7 +74,7 @@ addActionHandler('updateRecoveryEmail', async (global, actions, payload): Promis
|
||||
currentPassword, email, onSuccess,
|
||||
} = payload;
|
||||
|
||||
global = updateTwoFaSettings(global, { isLoading: true, error: undefined });
|
||||
global = updateTwoFaSettings(global, { isLoading: true, errorKey: undefined });
|
||||
setGlobal(global);
|
||||
|
||||
const isSuccess = await callApi('updateRecoveryEmail', currentPassword, email);
|
||||
@ -95,5 +95,5 @@ addActionHandler('provideTwoFaEmailCode', (global, actions, payload): ActionRetu
|
||||
});
|
||||
|
||||
addActionHandler('clearTwoFaError', (global): ActionReturnType => {
|
||||
return updateTwoFaSettings(global, { error: undefined });
|
||||
return updateTwoFaSettings(global, { errorKey: undefined });
|
||||
});
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
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;
|
||||
});
|
||||
@ -20,7 +20,7 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
||||
...global,
|
||||
twoFaSettings: {
|
||||
...global.twoFaSettings,
|
||||
error: update.message,
|
||||
errorKey: update.messageKey,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ import {
|
||||
clearStarPayment, openStarsTransactionModal,
|
||||
} from '../../reducers';
|
||||
import { updateTabState } from '../../reducers/tabs';
|
||||
import { selectChatMessage, selectStarsPayment } from '../../selectors';
|
||||
import { selectChatMessage, selectStarsPayment, selectTabState } from '../../selectors';
|
||||
|
||||
addActionHandler('processOriginStarsPayment', (global, actions, payload): ActionReturnType => {
|
||||
const { originData, status, tabId = getCurrentTabId() } = payload;
|
||||
@ -302,3 +302,35 @@ addActionHandler('closeGiftUpgradeModal', (global, actions, payload): ActionRetu
|
||||
giftUpgradeModal: undefined,
|
||||
}, tabId);
|
||||
});
|
||||
|
||||
addActionHandler('openGiftWithdrawModal', (global, actions, payload): ActionReturnType => {
|
||||
const { gift, tabId = getCurrentTabId() } = payload || {};
|
||||
|
||||
return updateTabState(global, {
|
||||
giftWithdrawModal: {
|
||||
gift,
|
||||
},
|
||||
}, tabId);
|
||||
});
|
||||
|
||||
addActionHandler('closeGiftWithdrawModal', (global, actions, payload): ActionReturnType => {
|
||||
const { tabId = getCurrentTabId() } = payload || {};
|
||||
|
||||
return updateTabState(global, {
|
||||
giftWithdrawModal: undefined,
|
||||
}, tabId);
|
||||
});
|
||||
|
||||
addActionHandler('clearGiftWithdrawError', (global, actions, payload): ActionReturnType => {
|
||||
const { tabId = getCurrentTabId() } = payload || {};
|
||||
const tabState = selectTabState(global, tabId);
|
||||
const giftWithdrawModal = tabState?.giftWithdrawModal;
|
||||
if (!giftWithdrawModal) return undefined;
|
||||
|
||||
return updateTabState(global, {
|
||||
giftWithdrawModal: {
|
||||
...giftWithdrawModal,
|
||||
errorKey: undefined,
|
||||
},
|
||||
}, tabId);
|
||||
});
|
||||
|
||||
38
src/global/actions/ui/statistics.ts
Normal file
38
src/global/actions/ui/statistics.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import type { ActionReturnType } from '../../types';
|
||||
|
||||
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
||||
import { addActionHandler } from '../..';
|
||||
import { updateVerifyMonetizationModal } from '../../reducers';
|
||||
import { updateTabState } from '../../reducers/tabs';
|
||||
|
||||
addActionHandler('openMonetizationVerificationModal', (global, actions, payload): ActionReturnType => {
|
||||
const { tabId = getCurrentTabId(), chatId } = payload || {};
|
||||
|
||||
return updateTabState(global, {
|
||||
monetizationVerificationModal: {
|
||||
chatId,
|
||||
},
|
||||
}, tabId);
|
||||
});
|
||||
|
||||
addActionHandler('closeMonetizationVerificationModal', (global, actions, payload): ActionReturnType => {
|
||||
const { tabId = getCurrentTabId() } = payload || {};
|
||||
|
||||
return updateTabState(global, {
|
||||
monetizationVerificationModal: undefined,
|
||||
}, tabId);
|
||||
});
|
||||
|
||||
addActionHandler('clearMonetizationVerificationError', (global, actions, payload): ActionReturnType => {
|
||||
const { tabId = getCurrentTabId() } = payload || {};
|
||||
|
||||
return updateVerifyMonetizationModal(global, { errorKey: undefined }, tabId);
|
||||
});
|
||||
|
||||
addActionHandler('closeMonetizationStatistics', (global, actions, payload): ActionReturnType => {
|
||||
const { tabId = getCurrentTabId() } = payload || {};
|
||||
|
||||
return updateTabState(global, {
|
||||
monetizationStatistics: undefined,
|
||||
}, tabId);
|
||||
});
|
||||
@ -428,11 +428,3 @@ addActionHandler('closeBoostStatistics', (global, actions, payload): ActionRetur
|
||||
boostStatistics: undefined,
|
||||
}, tabId);
|
||||
});
|
||||
|
||||
addActionHandler('closeMonetizationStatistics', (global, actions, payload): ActionReturnType => {
|
||||
const { tabId = getCurrentTabId() } = payload || {};
|
||||
|
||||
return updateTabState(global, {
|
||||
monetizationStatistics: undefined,
|
||||
}, tabId);
|
||||
});
|
||||
|
||||
@ -3,6 +3,7 @@ import type { OldLangFn } from '../../hooks/useOldLang';
|
||||
|
||||
import { ANONYMOUS_USER_ID, SERVICE_NOTIFICATIONS_USER_ID } from '../../config';
|
||||
import { formatFullDate, formatTime } from '../../util/dates/dateFormat';
|
||||
import { DAY } from '../../util/dates/units';
|
||||
import { orderBy } from '../../util/iteratees';
|
||||
import { formatPhoneNumber } from '../../util/phoneNumber';
|
||||
import { prepareSearchWordsForNeedle } from '../../util/searchWords';
|
||||
@ -227,11 +228,11 @@ export function sortUserIds(
|
||||
|
||||
switch (userStatus.type) {
|
||||
case 'userStatusRecently':
|
||||
return now - 60 * 60 * 24;
|
||||
return now - DAY;
|
||||
case 'userStatusLastWeek':
|
||||
return now - 60 * 60 * 24 * 7;
|
||||
return now - DAY * 7;
|
||||
case 'userStatusLastMonth':
|
||||
return now - 60 * 60 * 24 * 7 * 30;
|
||||
return now - DAY * 7 * 30;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -313,8 +313,6 @@ export const INITIAL_GLOBAL_STATE: GlobalState = {
|
||||
isMinimized: false,
|
||||
isHidden: false,
|
||||
},
|
||||
|
||||
monetizationInfo: {},
|
||||
};
|
||||
|
||||
export const INITIAL_TAB_STATE: TabState = {
|
||||
|
||||
@ -13,5 +13,4 @@ export * from './statistics';
|
||||
export * from './stories';
|
||||
export * from './translations';
|
||||
export * from './peers';
|
||||
export * from './password';
|
||||
export * from './topics';
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
import type { GlobalState } from '../types';
|
||||
|
||||
export function updateMonetizationInfo<T extends GlobalState>(
|
||||
global: T,
|
||||
update: GlobalState['monetizationInfo'],
|
||||
): T {
|
||||
return {
|
||||
...global,
|
||||
monetizationInfo: {
|
||||
...global.monetizationInfo,
|
||||
...update,
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -2,7 +2,7 @@ import type {
|
||||
ApiChannelMonetizationStatistics,
|
||||
ApiChannelStatistics, ApiGroupStatistics, ApiPostStatistics, StatisticsGraph,
|
||||
} from '../../api/types';
|
||||
import type { GlobalState, TabArgs } from '../types';
|
||||
import type { GlobalState, TabArgs, TabState } from '../types';
|
||||
|
||||
import { getCurrentTabId } from '../../util/establishMultitabRole';
|
||||
import { selectTabState } from '../selectors';
|
||||
@ -78,3 +78,20 @@ export function updateChannelMonetizationStatistics<T extends GlobalState>(
|
||||
},
|
||||
}, tabId);
|
||||
}
|
||||
|
||||
export function updateVerifyMonetizationModal<T extends GlobalState>(
|
||||
global: T, update: Partial<TabState['monetizationVerificationModal']>,
|
||||
...[tabId = getCurrentTabId()]: TabArgs<T>
|
||||
): T {
|
||||
const tabState = selectTabState(global, tabId);
|
||||
if (!tabState.monetizationVerificationModal) {
|
||||
return global;
|
||||
}
|
||||
|
||||
return updateTabState(global, {
|
||||
monetizationVerificationModal: {
|
||||
...tabState.monetizationVerificationModal,
|
||||
...update,
|
||||
},
|
||||
}, tabId);
|
||||
}
|
||||
|
||||
@ -173,7 +173,11 @@ export interface ActionPayloads {
|
||||
updatePerformanceSettings: Partial<PerformanceType>;
|
||||
loadPasswordInfo: undefined;
|
||||
clearTwoFaError: undefined;
|
||||
clearMonetizationInfo: undefined;
|
||||
openMonetizationVerificationModal: {
|
||||
chatId: string;
|
||||
} & WithTabId;
|
||||
clearMonetizationVerificationError: WithTabId | undefined;
|
||||
closeMonetizationVerificationModal: WithTabId | undefined;
|
||||
updatePassword: {
|
||||
currentPassword: string;
|
||||
password: string;
|
||||
@ -756,10 +760,9 @@ export interface ActionPayloads {
|
||||
peerId: string;
|
||||
} & WithTabId;
|
||||
|
||||
loadMonetizationRevenueWithdrawalUrl: {
|
||||
processMonetizationRevenueWithdrawalUrl: {
|
||||
peerId: string;
|
||||
currentPassword: string;
|
||||
onSuccess: VoidFunction;
|
||||
} & WithTabId;
|
||||
|
||||
// ui
|
||||
@ -2323,6 +2326,15 @@ export interface ActionPayloads {
|
||||
shouldKeepOriginalDetails?: boolean;
|
||||
upgradeStars?: number;
|
||||
} & WithTabId;
|
||||
openGiftWithdrawModal: {
|
||||
gift: ApiSavedStarGift;
|
||||
} & WithTabId;
|
||||
clearGiftWithdrawError: WithTabId | undefined;
|
||||
closeGiftWithdrawModal: WithTabId | undefined;
|
||||
processStarGiftWithdrawal: {
|
||||
gift: ApiInputSavedStarGift;
|
||||
password: string;
|
||||
} & WithTabId;
|
||||
loadPeerSavedGifts: {
|
||||
peerId: string;
|
||||
shouldRefresh?: boolean;
|
||||
|
||||
@ -109,15 +109,10 @@ export type GlobalState = {
|
||||
twoFaSettings: {
|
||||
hint?: string;
|
||||
isLoading?: boolean;
|
||||
error?: string;
|
||||
errorKey?: RegularLangFnParameters;
|
||||
waitingEmailCodeLength?: number;
|
||||
};
|
||||
|
||||
monetizationInfo: {
|
||||
isLoading?: boolean;
|
||||
error?: string;
|
||||
};
|
||||
|
||||
attachmentSettings: {
|
||||
shouldCompress: boolean;
|
||||
shouldSendGrouped: boolean;
|
||||
|
||||
@ -82,6 +82,7 @@ import type {
|
||||
} from '../../types';
|
||||
import type { WebApp, WebAppModalStateType } from '../../types/webapp';
|
||||
import type { SearchResultKey } from '../../util/keys/searchResultKey';
|
||||
import type { RegularLangFnParameters } from '../../util/localization';
|
||||
import type { CallbackAction } from './actions';
|
||||
|
||||
export type TabState = {
|
||||
@ -377,8 +378,8 @@ export type TabState = {
|
||||
receipt?: ApiReceiptRegular;
|
||||
error?: {
|
||||
field?: string;
|
||||
message?: string;
|
||||
description?: string;
|
||||
messageKey?: RegularLangFnParameters;
|
||||
descriptionKey?: RegularLangFnParameters;
|
||||
};
|
||||
isPaymentModalOpen?: boolean;
|
||||
isExtendedMedia?: boolean;
|
||||
@ -720,6 +721,12 @@ export type TabState = {
|
||||
gift?: ApiSavedStarGift;
|
||||
};
|
||||
|
||||
giftWithdrawModal?: {
|
||||
gift: ApiSavedStarGift;
|
||||
isLoading?: boolean;
|
||||
errorKey?: RegularLangFnParameters;
|
||||
};
|
||||
|
||||
suggestedStatusModal?: {
|
||||
botId: string;
|
||||
webAppKey?: string;
|
||||
@ -727,5 +734,11 @@ export type TabState = {
|
||||
duration?: number;
|
||||
};
|
||||
|
||||
monetizationVerificationModal?: {
|
||||
chatId: string;
|
||||
isLoading?: boolean;
|
||||
errorKey?: RegularLangFnParameters;
|
||||
};
|
||||
|
||||
isWaitingForStarGiftUpgrade?: true;
|
||||
};
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import type { RegularLangFnParameters } from '../../util/localization';
|
||||
import type { Dispatch, StateReducer } from '../useReducer';
|
||||
|
||||
import useReducer from '../useReducer';
|
||||
@ -21,7 +22,7 @@ export type FormState = {
|
||||
billingZip: string;
|
||||
saveInfo: boolean;
|
||||
saveCredentials: boolean;
|
||||
formErrors: Record<string, string>;
|
||||
formErrors: Partial<Record<string, RegularLangFnParameters>>;
|
||||
tipAmount: number;
|
||||
savedCredentialId: string;
|
||||
};
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import type TelegramClient from './TelegramClient';
|
||||
import type { WrappedError } from '../../../api/gramjs/helpers/misc';
|
||||
|
||||
import { EmailUnconfirmedError, PasswordModifiedError, RPCError } from '../errors';
|
||||
import { EmailUnconfirmedError } from '../errors';
|
||||
import Api from '../tl/api';
|
||||
|
||||
import { generateRandomBytes } from '../Helpers';
|
||||
@ -16,13 +17,8 @@ export interface TwoFaParams {
|
||||
onEmailCodeError?: (err: Error) => void;
|
||||
}
|
||||
|
||||
export interface TwoFaPasswordParams {
|
||||
currentPassword?: string;
|
||||
onPasswordCodeError?: (err: Error) => void;
|
||||
}
|
||||
|
||||
export type TmpPasswordResult = Api.account.TmpPassword | { error: string } | undefined;
|
||||
export type PasswordResult = Api.TypeInputCheckPasswordSRP | { error: string } | undefined;
|
||||
export type TmpPasswordResult = Api.account.TmpPassword | WrappedError | undefined;
|
||||
export type PasswordResult = Api.TypeInputCheckPasswordSRP | WrappedError | undefined;
|
||||
|
||||
/**
|
||||
* Changes the 2FA settings of the logged in user.
|
||||
@ -143,28 +139,17 @@ export async function getTmpPassword(client: TelegramClient, currentPassword: st
|
||||
}
|
||||
|
||||
const inputPassword = await computeCheck(pwd, currentPassword);
|
||||
try {
|
||||
const result = await client.invoke(new Api.account.GetTmpPassword({
|
||||
password: inputPassword,
|
||||
period: ttl,
|
||||
}));
|
||||
const result = await client.invoke(new Api.account.GetTmpPassword({
|
||||
password: inputPassword,
|
||||
period: ttl,
|
||||
}));
|
||||
|
||||
return result;
|
||||
} catch (err: unknown) {
|
||||
if (err instanceof RPCError && err.errorMessage === 'PASSWORD_HASH_INVALID') {
|
||||
return { error: err.errorMessage };
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function getCurrentPassword(
|
||||
client: TelegramClient,
|
||||
{
|
||||
currentPassword,
|
||||
onPasswordCodeError,
|
||||
}: TwoFaPasswordParams,
|
||||
currentPassword?: string,
|
||||
): Promise<PasswordResult> {
|
||||
const pwd = await client.invoke(new Api.account.GetPassword());
|
||||
|
||||
@ -172,16 +157,5 @@ export async function getCurrentPassword(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
return currentPassword ? await computeCheck(pwd, currentPassword!) : new Api.InputCheckPasswordEmpty();
|
||||
} catch (err: any) {
|
||||
if (err instanceof PasswordModifiedError) {
|
||||
onPasswordCodeError!(err);
|
||||
return undefined;
|
||||
} else if (err instanceof RPCError && err.errorMessage ==='PASSWORD_HASH_INVALID') {
|
||||
return { error: err.errorMessage };
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
return currentPassword ? await computeCheck(pwd, currentPassword!) : new Api.InputCheckPasswordEmpty();
|
||||
}
|
||||
|
||||
@ -24,7 +24,6 @@ import {
|
||||
TwoFaParams,
|
||||
TmpPasswordResult,
|
||||
PasswordResult,
|
||||
TwoFaPasswordParams,
|
||||
} from './2fa';
|
||||
import RequestState from '../network/RequestState';
|
||||
import Deferred from '../../../util/Deferred';
|
||||
@ -1264,8 +1263,8 @@ class TelegramClient {
|
||||
return getTmpPassword(this, currentPassword, ttl);
|
||||
}
|
||||
|
||||
getCurrentPassword(params: TwoFaPasswordParams): Promise<PasswordResult | undefined> {
|
||||
return getCurrentPassword(this, params);
|
||||
getCurrentPassword(currentPassword?: string): Promise<PasswordResult | undefined> {
|
||||
return getCurrentPassword(this, currentPassword);
|
||||
}
|
||||
|
||||
// event region
|
||||
|
||||
@ -136,7 +136,7 @@ export class EmailUnconfirmedError extends BadRequestError {
|
||||
}
|
||||
}
|
||||
|
||||
export class PasswordModifiedError extends BadRequestError {
|
||||
export class PasswordFreshError extends BadRequestError {
|
||||
public seconds: number;
|
||||
|
||||
constructor(args: any) {
|
||||
@ -159,6 +159,6 @@ export const rpcErrorRe = new Map<RegExp, any>([
|
||||
[/USER_MIGRATE_(\d+)/, UserMigrateError],
|
||||
[/NETWORK_MIGRATE_(\d+)/, NetworkMigrateError],
|
||||
[/EMAIL_UNCONFIRMED_(\d+)/, EmailUnconfirmedError],
|
||||
[/PASSWORD_TOO_FRESH_(\d+)/, PasswordModifiedError],
|
||||
[/PASSWORD_TOO_FRESH_(\d+)/, PasswordFreshError],
|
||||
[/^Timeout$/, TimedOutError],
|
||||
]);
|
||||
|
||||
@ -1722,6 +1722,7 @@ payments.upgradeStarGift#aed6e4f5 flags:# keep_original_details:flags.0?true sta
|
||||
payments.transferStarGift#7f18176a stargift:InputSavedStarGift to_id:InputPeer = Updates;
|
||||
payments.getUniqueStarGift#a1974d72 slug:string = payments.UniqueStarGift;
|
||||
payments.getSavedStarGifts#23830de9 flags:# exclude_unsaved:flags.0?true exclude_saved:flags.1?true exclude_unlimited:flags.2?true exclude_limited:flags.3?true exclude_unique:flags.4?true sort_by_value:flags.5?true peer:InputPeer offset:string limit:int = payments.SavedStarGifts;
|
||||
payments.getStarGiftWithdrawalUrl#d06e93a8 stargift:InputSavedStarGift password:InputCheckPasswordSRP = payments.StarGiftWithdrawalUrl;
|
||||
phone.requestCall#a6c4600c flags:# video:flags.0?true user_id:InputUser conference_call:flags.1?InputGroupCall random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
|
||||
phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
|
||||
phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall;
|
||||
|
||||
@ -310,6 +310,7 @@
|
||||
"payments.upgradeStarGift",
|
||||
"payments.transferStarGift",
|
||||
"payments.getUniqueStarGift",
|
||||
"payments.getStarGiftWithdrawalUrl",
|
||||
"langpack.getLangPack",
|
||||
"langpack.getStrings",
|
||||
"langpack.getLanguages",
|
||||
|
||||
@ -124,165 +124,166 @@ $icons-map: (
|
||||
"fontsize": "\f157",
|
||||
"forums": "\f158",
|
||||
"forward": "\f159",
|
||||
"fullscreen": "\f15a",
|
||||
"gifs": "\f15b",
|
||||
"gift": "\f15c",
|
||||
"group-filled": "\f15d",
|
||||
"group": "\f15e",
|
||||
"grouped-disable": "\f15f",
|
||||
"grouped": "\f160",
|
||||
"hand-stop": "\f161",
|
||||
"hashtag": "\f162",
|
||||
"heart-outline": "\f163",
|
||||
"heart": "\f164",
|
||||
"help": "\f165",
|
||||
"info-filled": "\f166",
|
||||
"info": "\f167",
|
||||
"install": "\f168",
|
||||
"italic": "\f169",
|
||||
"key": "\f16a",
|
||||
"keyboard": "\f16b",
|
||||
"lamp": "\f16c",
|
||||
"language": "\f16d",
|
||||
"large-pause": "\f16e",
|
||||
"large-play": "\f16f",
|
||||
"link-badge": "\f170",
|
||||
"link-broken": "\f171",
|
||||
"link": "\f172",
|
||||
"location": "\f173",
|
||||
"lock-badge": "\f174",
|
||||
"lock": "\f175",
|
||||
"logout": "\f176",
|
||||
"loop": "\f177",
|
||||
"mention": "\f178",
|
||||
"message-failed": "\f179",
|
||||
"message-pending": "\f17a",
|
||||
"message-read": "\f17b",
|
||||
"message-succeeded": "\f17c",
|
||||
"message": "\f17d",
|
||||
"microphone-alt": "\f17e",
|
||||
"microphone": "\f17f",
|
||||
"monospace": "\f180",
|
||||
"more-circle": "\f181",
|
||||
"more": "\f182",
|
||||
"move-caption-down": "\f183",
|
||||
"move-caption-up": "\f184",
|
||||
"mute": "\f185",
|
||||
"muted": "\f186",
|
||||
"my-notes": "\f187",
|
||||
"new-chat-filled": "\f188",
|
||||
"next": "\f189",
|
||||
"nochannel": "\f18a",
|
||||
"noise-suppression": "\f18b",
|
||||
"non-contacts": "\f18c",
|
||||
"one-filled": "\f18d",
|
||||
"open-in-new-tab": "\f18e",
|
||||
"password-off": "\f18f",
|
||||
"pause": "\f190",
|
||||
"permissions": "\f191",
|
||||
"phone-discard-outline": "\f192",
|
||||
"phone-discard": "\f193",
|
||||
"phone": "\f194",
|
||||
"photo": "\f195",
|
||||
"pin-badge": "\f196",
|
||||
"pin-list": "\f197",
|
||||
"pin": "\f198",
|
||||
"pinned-chat": "\f199",
|
||||
"pinned-message": "\f19a",
|
||||
"pip": "\f19b",
|
||||
"play-story": "\f19c",
|
||||
"play": "\f19d",
|
||||
"poll": "\f19e",
|
||||
"previous": "\f19f",
|
||||
"privacy-policy": "\f1a0",
|
||||
"quote-text": "\f1a1",
|
||||
"quote": "\f1a2",
|
||||
"readchats": "\f1a3",
|
||||
"recent": "\f1a4",
|
||||
"reload": "\f1a5",
|
||||
"remove-quote": "\f1a6",
|
||||
"remove": "\f1a7",
|
||||
"reopen-topic": "\f1a8",
|
||||
"replace": "\f1a9",
|
||||
"replies": "\f1aa",
|
||||
"reply-filled": "\f1ab",
|
||||
"reply": "\f1ac",
|
||||
"revenue-split": "\f1ad",
|
||||
"revote": "\f1ae",
|
||||
"save-story": "\f1af",
|
||||
"saved-messages": "\f1b0",
|
||||
"schedule": "\f1b1",
|
||||
"search": "\f1b2",
|
||||
"select": "\f1b3",
|
||||
"send-outline": "\f1b4",
|
||||
"send": "\f1b5",
|
||||
"settings-filled": "\f1b6",
|
||||
"settings": "\f1b7",
|
||||
"share-filled": "\f1b8",
|
||||
"share-screen-outlined": "\f1b9",
|
||||
"share-screen-stop": "\f1ba",
|
||||
"share-screen": "\f1bb",
|
||||
"show-message": "\f1bc",
|
||||
"sidebar": "\f1bd",
|
||||
"skip-next": "\f1be",
|
||||
"skip-previous": "\f1bf",
|
||||
"smallscreen": "\f1c0",
|
||||
"smile": "\f1c1",
|
||||
"sort": "\f1c2",
|
||||
"speaker-muted-story": "\f1c3",
|
||||
"speaker-outline": "\f1c4",
|
||||
"speaker-story": "\f1c5",
|
||||
"speaker": "\f1c6",
|
||||
"spoiler-disable": "\f1c7",
|
||||
"spoiler": "\f1c8",
|
||||
"sport": "\f1c9",
|
||||
"star": "\f1ca",
|
||||
"stars-lock": "\f1cb",
|
||||
"stats": "\f1cc",
|
||||
"stealth-future": "\f1cd",
|
||||
"stealth-past": "\f1ce",
|
||||
"stickers": "\f1cf",
|
||||
"stop-raising-hand": "\f1d0",
|
||||
"stop": "\f1d1",
|
||||
"story-caption": "\f1d2",
|
||||
"story-expired": "\f1d3",
|
||||
"story-priority": "\f1d4",
|
||||
"story-reply": "\f1d5",
|
||||
"strikethrough": "\f1d6",
|
||||
"tag-add": "\f1d7",
|
||||
"tag-crossed": "\f1d8",
|
||||
"tag-filter": "\f1d9",
|
||||
"tag-name": "\f1da",
|
||||
"tag": "\f1db",
|
||||
"timer": "\f1dc",
|
||||
"toncoin": "\f1dd",
|
||||
"trade": "\f1de",
|
||||
"transcribe": "\f1df",
|
||||
"truck": "\f1e0",
|
||||
"unarchive": "\f1e1",
|
||||
"underlined": "\f1e2",
|
||||
"unlock-badge": "\f1e3",
|
||||
"unlock": "\f1e4",
|
||||
"unmute": "\f1e5",
|
||||
"unpin": "\f1e6",
|
||||
"unread": "\f1e7",
|
||||
"up": "\f1e8",
|
||||
"user-filled": "\f1e9",
|
||||
"user-online": "\f1ea",
|
||||
"user": "\f1eb",
|
||||
"video-outlined": "\f1ec",
|
||||
"video-stop": "\f1ed",
|
||||
"video": "\f1ee",
|
||||
"view-once": "\f1ef",
|
||||
"voice-chat": "\f1f0",
|
||||
"volume-1": "\f1f1",
|
||||
"volume-2": "\f1f2",
|
||||
"volume-3": "\f1f3",
|
||||
"web": "\f1f4",
|
||||
"webapp": "\f1f5",
|
||||
"word-wrap": "\f1f6",
|
||||
"zoom-in": "\f1f7",
|
||||
"zoom-out": "\f1f8",
|
||||
"fragment": "\f15a",
|
||||
"fullscreen": "\f15b",
|
||||
"gifs": "\f15c",
|
||||
"gift": "\f15d",
|
||||
"group-filled": "\f15e",
|
||||
"group": "\f15f",
|
||||
"grouped-disable": "\f160",
|
||||
"grouped": "\f161",
|
||||
"hand-stop": "\f162",
|
||||
"hashtag": "\f163",
|
||||
"heart-outline": "\f164",
|
||||
"heart": "\f165",
|
||||
"help": "\f166",
|
||||
"info-filled": "\f167",
|
||||
"info": "\f168",
|
||||
"install": "\f169",
|
||||
"italic": "\f16a",
|
||||
"key": "\f16b",
|
||||
"keyboard": "\f16c",
|
||||
"lamp": "\f16d",
|
||||
"language": "\f16e",
|
||||
"large-pause": "\f16f",
|
||||
"large-play": "\f170",
|
||||
"link-badge": "\f171",
|
||||
"link-broken": "\f172",
|
||||
"link": "\f173",
|
||||
"location": "\f174",
|
||||
"lock-badge": "\f175",
|
||||
"lock": "\f176",
|
||||
"logout": "\f177",
|
||||
"loop": "\f178",
|
||||
"mention": "\f179",
|
||||
"message-failed": "\f17a",
|
||||
"message-pending": "\f17b",
|
||||
"message-read": "\f17c",
|
||||
"message-succeeded": "\f17d",
|
||||
"message": "\f17e",
|
||||
"microphone-alt": "\f17f",
|
||||
"microphone": "\f180",
|
||||
"monospace": "\f181",
|
||||
"more-circle": "\f182",
|
||||
"more": "\f183",
|
||||
"move-caption-down": "\f184",
|
||||
"move-caption-up": "\f185",
|
||||
"mute": "\f186",
|
||||
"muted": "\f187",
|
||||
"my-notes": "\f188",
|
||||
"new-chat-filled": "\f189",
|
||||
"next": "\f18a",
|
||||
"nochannel": "\f18b",
|
||||
"noise-suppression": "\f18c",
|
||||
"non-contacts": "\f18d",
|
||||
"one-filled": "\f18e",
|
||||
"open-in-new-tab": "\f18f",
|
||||
"password-off": "\f190",
|
||||
"pause": "\f191",
|
||||
"permissions": "\f192",
|
||||
"phone-discard-outline": "\f193",
|
||||
"phone-discard": "\f194",
|
||||
"phone": "\f195",
|
||||
"photo": "\f196",
|
||||
"pin-badge": "\f197",
|
||||
"pin-list": "\f198",
|
||||
"pin": "\f199",
|
||||
"pinned-chat": "\f19a",
|
||||
"pinned-message": "\f19b",
|
||||
"pip": "\f19c",
|
||||
"play-story": "\f19d",
|
||||
"play": "\f19e",
|
||||
"poll": "\f19f",
|
||||
"previous": "\f1a0",
|
||||
"privacy-policy": "\f1a1",
|
||||
"quote-text": "\f1a2",
|
||||
"quote": "\f1a3",
|
||||
"readchats": "\f1a4",
|
||||
"recent": "\f1a5",
|
||||
"reload": "\f1a6",
|
||||
"remove-quote": "\f1a7",
|
||||
"remove": "\f1a8",
|
||||
"reopen-topic": "\f1a9",
|
||||
"replace": "\f1aa",
|
||||
"replies": "\f1ab",
|
||||
"reply-filled": "\f1ac",
|
||||
"reply": "\f1ad",
|
||||
"revenue-split": "\f1ae",
|
||||
"revote": "\f1af",
|
||||
"save-story": "\f1b0",
|
||||
"saved-messages": "\f1b1",
|
||||
"schedule": "\f1b2",
|
||||
"search": "\f1b3",
|
||||
"select": "\f1b4",
|
||||
"send-outline": "\f1b5",
|
||||
"send": "\f1b6",
|
||||
"settings-filled": "\f1b7",
|
||||
"settings": "\f1b8",
|
||||
"share-filled": "\f1b9",
|
||||
"share-screen-outlined": "\f1ba",
|
||||
"share-screen-stop": "\f1bb",
|
||||
"share-screen": "\f1bc",
|
||||
"show-message": "\f1bd",
|
||||
"sidebar": "\f1be",
|
||||
"skip-next": "\f1bf",
|
||||
"skip-previous": "\f1c0",
|
||||
"smallscreen": "\f1c1",
|
||||
"smile": "\f1c2",
|
||||
"sort": "\f1c3",
|
||||
"speaker-muted-story": "\f1c4",
|
||||
"speaker-outline": "\f1c5",
|
||||
"speaker-story": "\f1c6",
|
||||
"speaker": "\f1c7",
|
||||
"spoiler-disable": "\f1c8",
|
||||
"spoiler": "\f1c9",
|
||||
"sport": "\f1ca",
|
||||
"star": "\f1cb",
|
||||
"stars-lock": "\f1cc",
|
||||
"stats": "\f1cd",
|
||||
"stealth-future": "\f1ce",
|
||||
"stealth-past": "\f1cf",
|
||||
"stickers": "\f1d0",
|
||||
"stop-raising-hand": "\f1d1",
|
||||
"stop": "\f1d2",
|
||||
"story-caption": "\f1d3",
|
||||
"story-expired": "\f1d4",
|
||||
"story-priority": "\f1d5",
|
||||
"story-reply": "\f1d6",
|
||||
"strikethrough": "\f1d7",
|
||||
"tag-add": "\f1d8",
|
||||
"tag-crossed": "\f1d9",
|
||||
"tag-filter": "\f1da",
|
||||
"tag-name": "\f1db",
|
||||
"tag": "\f1dc",
|
||||
"timer": "\f1dd",
|
||||
"toncoin": "\f1de",
|
||||
"trade": "\f1df",
|
||||
"transcribe": "\f1e0",
|
||||
"truck": "\f1e1",
|
||||
"unarchive": "\f1e2",
|
||||
"underlined": "\f1e3",
|
||||
"unlock-badge": "\f1e4",
|
||||
"unlock": "\f1e5",
|
||||
"unmute": "\f1e6",
|
||||
"unpin": "\f1e7",
|
||||
"unread": "\f1e8",
|
||||
"up": "\f1e9",
|
||||
"user-filled": "\f1ea",
|
||||
"user-online": "\f1eb",
|
||||
"user": "\f1ec",
|
||||
"video-outlined": "\f1ed",
|
||||
"video-stop": "\f1ee",
|
||||
"video": "\f1ef",
|
||||
"view-once": "\f1f0",
|
||||
"voice-chat": "\f1f1",
|
||||
"volume-1": "\f1f2",
|
||||
"volume-2": "\f1f3",
|
||||
"volume-3": "\f1f4",
|
||||
"web": "\f1f5",
|
||||
"webapp": "\f1f6",
|
||||
"word-wrap": "\f1f7",
|
||||
"zoom-in": "\f1f8",
|
||||
"zoom-out": "\f1f9",
|
||||
);
|
||||
|
||||
.icon-active-sessions::before {
|
||||
@ -552,6 +553,9 @@ $icons-map: (
|
||||
.icon-forward::before {
|
||||
content: map.get($icons-map, "forward");
|
||||
}
|
||||
.icon-fragment::before {
|
||||
content: map.get($icons-map, "fragment");
|
||||
}
|
||||
.icon-fullscreen::before {
|
||||
content: map.get($icons-map, "fullscreen");
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -88,6 +88,7 @@ export type FontIconName =
|
||||
| 'fontsize'
|
||||
| 'forums'
|
||||
| 'forward'
|
||||
| 'fragment'
|
||||
| 'fullscreen'
|
||||
| 'gifs'
|
||||
| 'gift'
|
||||
|
||||
28
src/types/language.d.ts
vendored
28
src/types/language.d.ts
vendored
@ -590,10 +590,17 @@ export interface LangPair {
|
||||
'ErrorSendRestrictedStickersAll': undefined;
|
||||
'ErrorPhoneNumberInvalid': undefined;
|
||||
'ErrorCodeInvalid': undefined;
|
||||
'ErrorEmailCodeInvalid': undefined;
|
||||
'ErrorIncorrectPassword': undefined;
|
||||
'ErrorPasswordFlood': undefined;
|
||||
'ErrorPhoneBanned': undefined;
|
||||
'ErrorUnexpected': undefined;
|
||||
'ErrorEmailUnconfirmed': undefined;
|
||||
'ErrorEmailHashExpired': undefined;
|
||||
'ErrorNewSaltInvalid': undefined;
|
||||
'ErrorPasswordChanged': undefined;
|
||||
'ErrorPasswordMissing': undefined;
|
||||
'ErrorUnspecified': undefined;
|
||||
'NoStickers': undefined;
|
||||
'ClearRecentEmoji': undefined;
|
||||
'TextFormatAddLinkTitle': undefined;
|
||||
@ -1190,6 +1197,7 @@ export interface LangPair {
|
||||
'GiftInfoViewUpgraded': undefined;
|
||||
'GiftInfoUpgradeBadge': undefined;
|
||||
'GiftInfoUpgradeForFree': undefined;
|
||||
'GiftInfoWithdraw': undefined;
|
||||
'GiftUpgradeUniqueTitle': undefined;
|
||||
'GiftUpgradeUniqueDescription': undefined;
|
||||
'GiftUpgradeTransferableTitle': undefined;
|
||||
@ -1203,6 +1211,8 @@ export interface LangPair {
|
||||
'GiftUpgradedDescription': undefined;
|
||||
'GiftMakeUniqueAcc': undefined;
|
||||
'GiftMakeUniqueLink': undefined;
|
||||
'GiftWithdrawTitle': undefined;
|
||||
'GiftWithdrawSubmit': undefined;
|
||||
'AllGiftsCategory': undefined;
|
||||
'LimitedGiftsCategory': undefined;
|
||||
'StockGiftsCategory': undefined;
|
||||
@ -1296,6 +1306,9 @@ export interface LangPair {
|
||||
'ViewButtonGiftUnique': undefined;
|
||||
'AuthContinueOnThisLanguage': undefined;
|
||||
'Share': undefined;
|
||||
'CheckPasswordTitle': undefined;
|
||||
'CheckPasswordPlaceholder': undefined;
|
||||
'CheckPasswordDescription': undefined;
|
||||
}
|
||||
|
||||
export interface LangPairWithVariables<V extends unknown = LangVariable> {
|
||||
@ -1461,6 +1474,12 @@ export interface LangPairWithVariables<V extends unknown = LangVariable> {
|
||||
'SlowModeHint': {
|
||||
'time': V;
|
||||
};
|
||||
'ErrorFloodTime': {
|
||||
'time': V;
|
||||
};
|
||||
'ErrorPasswordFresh': {
|
||||
'time': V;
|
||||
};
|
||||
'ErrorUnexpectedMessage': {
|
||||
'error': V;
|
||||
};
|
||||
@ -1707,6 +1726,9 @@ export interface LangPairWithVariables<V extends unknown = LangVariable> {
|
||||
'peer': V;
|
||||
'link': V;
|
||||
};
|
||||
'GiftWithdrawDescription': {
|
||||
'gift': V;
|
||||
};
|
||||
'StarsAmount': {
|
||||
'amount': V;
|
||||
};
|
||||
@ -1829,9 +1851,6 @@ export interface LangPairPluralWithVariables<V extends unknown = LangVariable> {
|
||||
'PreviewSenderSendFile': {
|
||||
'count': V;
|
||||
};
|
||||
'ErrorFlood': {
|
||||
'hour': V;
|
||||
};
|
||||
'PinnedMessageTitle': {
|
||||
'index': V;
|
||||
};
|
||||
@ -1958,6 +1977,9 @@ export interface LangPairPluralWithVariables<V extends unknown = LangVariable> {
|
||||
'count': V;
|
||||
'total': V;
|
||||
};
|
||||
'GiftWithdrawWait': {
|
||||
'days': V;
|
||||
};
|
||||
'StarsAmountText': {
|
||||
'amount': V;
|
||||
};
|
||||
|
||||
19
src/util/dates/units.ts
Normal file
19
src/util/dates/units.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/// In seconds
|
||||
export const MINUTE = 60;
|
||||
export const HOUR = 3600;
|
||||
export const DAY = 86400;
|
||||
|
||||
export function getMinutes(seconds: number, roundDown?: boolean) {
|
||||
const roundFunc = roundDown ? Math.floor : Math.ceil;
|
||||
return roundFunc(seconds / MINUTE);
|
||||
}
|
||||
|
||||
export function getHours(seconds: number, roundDown?: boolean) {
|
||||
const roundFunc = roundDown ? Math.floor : Math.ceil;
|
||||
return roundFunc(seconds / HOUR);
|
||||
}
|
||||
|
||||
export function getDays(seconds: number, roundDown?: boolean) {
|
||||
const roundFunc = roundDown ? Math.floor : Math.ceil;
|
||||
return roundFunc(seconds / DAY);
|
||||
}
|
||||
@ -361,7 +361,7 @@ function getString(langKey: LangKey, count: number) {
|
||||
|
||||
function processTranslation(
|
||||
langKey: LangKey,
|
||||
variables?: Record<string, LangVariable>,
|
||||
variables?: Record<string, LangVariable | RegularLangFnParameters>,
|
||||
options?: LangFnOptions | LangFnOptionsWithPlural,
|
||||
): string {
|
||||
const cacheKey = `${langKey}-${JSON.stringify(variables)}-${JSON.stringify(options)}`;
|
||||
@ -377,6 +377,9 @@ function processTranslation(
|
||||
const variableEntries = variables ? Object.entries(variables) : [];
|
||||
const finalString = variableEntries.reduce((result, [key, value]) => {
|
||||
if (value === undefined) return result;
|
||||
if (typeof value === 'object') { // Allow recursive variables in basic `lang.with`
|
||||
value = processTranslation(value.key, value.variables, value.options);
|
||||
}
|
||||
|
||||
const valueAsString = Number.isFinite(value) ? formatters!.number.format(value as number) : String(value);
|
||||
return result.replace(`{${key}}`, valueAsString);
|
||||
|
||||
@ -11,6 +11,7 @@ import type { TextFilter } from '../../components/common/helpers/renderText';
|
||||
import type {
|
||||
LangPairPluralWithVariables,
|
||||
LangPairWithVariables,
|
||||
LangVariable,
|
||||
PluralLangKey,
|
||||
PluralLangKeyWithVariables,
|
||||
RegularLangKey,
|
||||
@ -55,7 +56,9 @@ type RegularLangFnParametersWithoutVariables = {
|
||||
type RegularLangFnParametersWithVariables<T = LangPairWithVariables> = {
|
||||
[K in keyof T]: {
|
||||
key: K;
|
||||
variables: T[K];
|
||||
variables: {
|
||||
[key in keyof T[K]]: LangVariable | RegularLangFnParameters;
|
||||
};
|
||||
options?: LangFnOptions;
|
||||
}
|
||||
}[keyof T];
|
||||
@ -69,7 +72,9 @@ type RegularLangFnPluralParameters = {
|
||||
type RegularLangFnPluralParametersWithVariables<T = LangPairPluralWithVariables> = {
|
||||
[K in keyof T]: {
|
||||
key: K;
|
||||
variables: T[K];
|
||||
variables: {
|
||||
[key in keyof T[K]]: LangVariable | RegularLangFnParameters;
|
||||
};
|
||||
options: LangFnOptionsWithPlural;
|
||||
}
|
||||
}[keyof T];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user