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 { numberToHexColor } from '../../../util/colors';
|
||||||
import { pick } from '../../../util/iteratees';
|
import { pick } from '../../../util/iteratees';
|
||||||
import { addDocumentToLocalDb } from '../helpers';
|
import { addDocumentToLocalDb } from '../helpers/localDb';
|
||||||
import { buildApiPhoto, buildApiThumbnailFromStripped } from './common';
|
import { buildApiPhoto, buildApiThumbnailFromStripped } from './common';
|
||||||
import { omitVirtualClassFields } from './helpers';
|
import { omitVirtualClassFields } from './helpers';
|
||||||
import { buildApiDocument, buildApiWebDocument, buildVideoFromDocument } from './messageContent';
|
import { buildApiDocument, buildApiWebDocument, buildVideoFromDocument } from './messageContent';
|
||||||
|
|||||||
@ -25,7 +25,8 @@ import type {
|
|||||||
|
|
||||||
import { pick, pickTruthy } from '../../../util/iteratees';
|
import { pick, pickTruthy } from '../../../util/iteratees';
|
||||||
import { getServerTime, getServerTimeOffset } from '../../../util/serverTime';
|
import { getServerTime, getServerTimeOffset } from '../../../util/serverTime';
|
||||||
import { addPhotoToLocalDb, addUserToLocalDb, serializeBytes } from '../helpers';
|
import { addPhotoToLocalDb, addUserToLocalDb } from '../helpers/localDb';
|
||||||
|
import { serializeBytes } from '../helpers/misc';
|
||||||
import {
|
import {
|
||||||
buildApiBotVerification, buildApiFormattedText, buildApiPhoto, buildApiUsernames, buildAvatarPhotoId,
|
buildApiBotVerification, buildApiFormattedText, buildApiPhoto, buildApiUsernames, buildAvatarPhotoId,
|
||||||
} from './common';
|
} from './common';
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import type {
|
|||||||
} from '../../types';
|
} from '../../types';
|
||||||
|
|
||||||
import { numberToHexColor } from '../../../util/colors';
|
import { numberToHexColor } from '../../../util/colors';
|
||||||
import { addDocumentToLocalDb } from '../helpers';
|
import { addDocumentToLocalDb } from '../helpers/localDb';
|
||||||
import { buildApiFormattedText } from './common';
|
import { buildApiFormattedText } from './common';
|
||||||
import { getApiChatIdFromMtpPeer } from './peers';
|
import { getApiChatIdFromMtpPeer } from './peers';
|
||||||
import { buildStickerFromDocument } from './symbols';
|
import { buildStickerFromDocument } from './symbols';
|
||||||
@ -129,7 +129,7 @@ export function buildApiStarGiftAttribute(attribute: GramJs.TypeStarGiftAttribut
|
|||||||
export function buildApiSavedStarGift(userStarGift: GramJs.SavedStarGift, peerId: string): ApiSavedStarGift {
|
export function buildApiSavedStarGift(userStarGift: GramJs.SavedStarGift, peerId: string): ApiSavedStarGift {
|
||||||
const {
|
const {
|
||||||
gift, date, convertStars, fromId, message, msgId, nameHidden, unsaved, upgradeStars, transferStars, canUpgrade,
|
gift, date, convertStars, fromId, message, msgId, nameHidden, unsaved, upgradeStars, transferStars, canUpgrade,
|
||||||
savedId,
|
savedId, canExportAt,
|
||||||
} = userStarGift;
|
} = userStarGift;
|
||||||
|
|
||||||
const inputGift: ApiInputSavedStarGift | undefined = savedId && peerId
|
const inputGift: ApiInputSavedStarGift | undefined = savedId && peerId
|
||||||
@ -150,5 +150,6 @@ export function buildApiSavedStarGift(userStarGift: GramJs.SavedStarGift, peerId
|
|||||||
transferStars: transferStars?.toJSNumber(),
|
transferStars: transferStars?.toJSNumber(),
|
||||||
inputGift,
|
inputGift,
|
||||||
savedId: savedId?.toString(),
|
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 { generateWaveform } from '../../../util/generateWaveform';
|
||||||
import { pick } from '../../../util/iteratees';
|
import { pick } from '../../../util/iteratees';
|
||||||
import {
|
import {
|
||||||
addMediaToLocalDb, addStoryToLocalDb, type MediaRepairContext, serializeBytes,
|
addMediaToLocalDb, addStoryToLocalDb, type MediaRepairContext,
|
||||||
} from '../helpers';
|
} from '../helpers/localDb';
|
||||||
|
import { serializeBytes } from '../helpers/misc';
|
||||||
import {
|
import {
|
||||||
buildApiFormattedText,
|
buildApiFormattedText,
|
||||||
buildApiMessageEntity,
|
buildApiMessageEntity,
|
||||||
|
|||||||
@ -58,9 +58,8 @@ import { buildPeer } from '../gramjsBuilders';
|
|||||||
import {
|
import {
|
||||||
addPhotoToLocalDb,
|
addPhotoToLocalDb,
|
||||||
type MediaRepairContext,
|
type MediaRepairContext,
|
||||||
resolveMessageApiChatId,
|
} from '../helpers/localDb';
|
||||||
serializeBytes,
|
import { resolveMessageApiChatId, serializeBytes } from '../helpers/misc';
|
||||||
} from '../helpers';
|
|
||||||
import { buildApiCallDiscardReason } from './calls';
|
import { buildApiCallDiscardReason } from './calls';
|
||||||
import {
|
import {
|
||||||
buildApiFormattedText,
|
buildApiFormattedText,
|
||||||
|
|||||||
@ -22,7 +22,7 @@ import {
|
|||||||
buildCollectionByCallback, omit, omitUndefined, pick,
|
buildCollectionByCallback, omit, omitUndefined, pick,
|
||||||
} from '../../../util/iteratees';
|
} from '../../../util/iteratees';
|
||||||
import { getServerTime } from '../../../util/serverTime';
|
import { getServerTime } from '../../../util/serverTime';
|
||||||
import { addUserToLocalDb } from '../helpers';
|
import { addUserToLocalDb } from '../helpers/localDb';
|
||||||
import { omitVirtualClassFields } from './helpers';
|
import { omitVirtualClassFields } from './helpers';
|
||||||
import { buildApiDocument, buildMessageTextContent } from './messageContent';
|
import { buildApiDocument, buildMessageTextContent } from './messageContent';
|
||||||
import { buildApiPeerId, getApiChatIdFromMtpPeer } from './peers';
|
import { buildApiPeerId, getApiChatIdFromMtpPeer } from './peers';
|
||||||
|
|||||||
@ -29,7 +29,7 @@ import type {
|
|||||||
BoughtPaidMedia,
|
BoughtPaidMedia,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
|
|
||||||
import { addWebDocumentToLocalDb } from '../helpers';
|
import { addWebDocumentToLocalDb } from '../helpers/localDb';
|
||||||
import { buildApiStarsSubscriptionPricing } from './chats';
|
import { buildApiStarsSubscriptionPricing } from './chats';
|
||||||
import { buildApiMessageEntity } from './common';
|
import { buildApiMessageEntity } from './common';
|
||||||
import { buildApiStarGift } from './gifts';
|
import { buildApiStarGift } from './gifts';
|
||||||
|
|||||||
@ -37,7 +37,7 @@ import {
|
|||||||
|
|
||||||
import { CHANNEL_ID_LENGTH, DEFAULT_STATUS_ICON_ID } from '../../../config';
|
import { CHANNEL_ID_LENGTH, DEFAULT_STATUS_ICON_ID } from '../../../config';
|
||||||
import { pick } from '../../../util/iteratees';
|
import { pick } from '../../../util/iteratees';
|
||||||
import { deserializeBytes } from '../helpers';
|
import { deserializeBytes } from '../helpers/misc';
|
||||||
import localDb from '../localDb';
|
import localDb from '../localDb';
|
||||||
|
|
||||||
function checkIfChannelId(id: string) {
|
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, { 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',
|
|
||||||
};
|
|
||||||
|
|
||||||
export type MessageRepairContext = Pick<GramJs.TypeMessage, 'peerId' | 'id'>;
|
export type MessageRepairContext = Pick<GramJs.TypeMessage, 'peerId' | 'id'>;
|
||||||
export type MediaRepairContext = MessageRepairContext;
|
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) {
|
export function addMessageToLocalDb(message: GramJs.TypeMessage | GramJs.TypeSponsoredMessage) {
|
||||||
if (message instanceof GramJs.Message) {
|
if (message instanceof GramJs.Message) {
|
||||||
if (message.media) addMediaToLocalDb(message.media, message);
|
if (message.media) addMediaToLocalDb(message.media, message);
|
||||||
@ -204,33 +173,3 @@ export function addUserToLocalDb(user: GramJs.User) {
|
|||||||
export function addWebDocumentToLocalDb(webDocument: GramJs.TypeWebDocument) {
|
export function addWebDocumentToLocalDb(webDocument: GramJs.TypeWebDocument) {
|
||||||
localDb.webDocuments[webDocument.url] = webDocument;
|
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 {
|
import type {
|
||||||
ApiUpdateAuthorizationState,
|
ApiUpdateAuthorizationState,
|
||||||
ApiUpdateAuthorizationStateType,
|
ApiUpdateAuthorizationStateType,
|
||||||
@ -9,17 +5,9 @@ import type {
|
|||||||
ApiUserFullInfo,
|
ApiUserFullInfo,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
|
|
||||||
import { DEBUG } from '../../../config';
|
import { wrapError } from '../helpers/misc';
|
||||||
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
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: {
|
const authController: {
|
||||||
resolve?: Function;
|
resolve?: Function;
|
||||||
reject?: Function;
|
reject?: Function;
|
||||||
@ -87,36 +75,7 @@ export function onRequestQrCode(qrCode: { token: Buffer; expires: number }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function onAuthError(err: Error) {
|
export function onAuthError(err: Error) {
|
||||||
let messageKey: RegularLangFnParameters | undefined;
|
const { messageKey } = wrapError(err);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sendApiUpdate({
|
sendApiUpdate({
|
||||||
'@type': 'updateAuthorizationError',
|
'@type': 'updateAuthorizationError',
|
||||||
|
|||||||
@ -39,8 +39,8 @@ import {
|
|||||||
addPhotoToLocalDb,
|
addPhotoToLocalDb,
|
||||||
addUserToLocalDb,
|
addUserToLocalDb,
|
||||||
addWebDocumentToLocalDb,
|
addWebDocumentToLocalDb,
|
||||||
deserializeBytes,
|
} from '../helpers/localDb';
|
||||||
} from '../helpers';
|
import { deserializeBytes } from '../helpers/misc';
|
||||||
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
||||||
import { invokeRequest } from './client';
|
import { invokeRequest } from './client';
|
||||||
|
|
||||||
|
|||||||
@ -69,8 +69,8 @@ import {
|
|||||||
} from '../gramjsBuilders';
|
} from '../gramjsBuilders';
|
||||||
import {
|
import {
|
||||||
addPhotoToLocalDb,
|
addPhotoToLocalDb,
|
||||||
isChatFolder,
|
} from '../helpers/localDb';
|
||||||
} from '../helpers';
|
import { isChatFolder } from '../helpers/misc';
|
||||||
import { scheduleMutedChatUpdate } from '../scheduleUnmute';
|
import { scheduleMutedChatUpdate } from '../scheduleUnmute';
|
||||||
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
||||||
import {
|
import {
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import {
|
|||||||
sessions,
|
sessions,
|
||||||
type Update,
|
type Update,
|
||||||
} from '../../../lib/gramjs';
|
} 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 TelegramClient from '../../../lib/gramjs/client/TelegramClient';
|
||||||
import { RPCError } from '../../../lib/gramjs/errors';
|
import { RPCError } from '../../../lib/gramjs/errors';
|
||||||
import { Logger as GramJsLogger } from '../../../lib/gramjs/extensions/index';
|
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 { buildApiUser, buildApiUserFullInfo } from '../apiBuilders/users';
|
||||||
import { buildInputPeerFromLocalDb, getEntityTypeById } from '../gramjsBuilders';
|
import { buildInputPeerFromLocalDb, getEntityTypeById } from '../gramjsBuilders';
|
||||||
import {
|
import {
|
||||||
addStoryToLocalDb, addUserToLocalDb, isResponseUpdate, log,
|
addStoryToLocalDb, addUserToLocalDb,
|
||||||
} from '../helpers';
|
} from '../helpers/localDb';
|
||||||
|
import {
|
||||||
|
isResponseUpdate, log,
|
||||||
|
} from '../helpers/misc';
|
||||||
import localDb, { clearLocalDb, type RepairInfo } from '../localDb';
|
import localDb, { clearLocalDb, type RepairInfo } from '../localDb';
|
||||||
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
||||||
import { processAndUpdateEntities, processMessageAndUpdateThreadInfo } from '../updates/entityProcessor';
|
import { processAndUpdateEntities, processMessageAndUpdateThreadInfo } from '../updates/entityProcessor';
|
||||||
@ -376,8 +379,8 @@ export function getTmpPassword(currentPassword: string, ttl?: number) {
|
|||||||
return client.getTmpPassword(currentPassword, ttl);
|
return client.getTmpPassword(currentPassword, ttl);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCurrentPassword(params: TwoFaPasswordParams) {
|
export function getCurrentPassword(currentPassword?: string) {
|
||||||
return client.getCurrentPassword(params);
|
return client.getCurrentPassword(currentPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function abortChatRequests(params: { chatId: string; threadId?: ThreadId }) {
|
export function abortChatRequests(params: { chatId: string; threadId?: ThreadId }) {
|
||||||
|
|||||||
@ -89,7 +89,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
deserializeBytes,
|
deserializeBytes,
|
||||||
resolveMessageApiChatId,
|
resolveMessageApiChatId,
|
||||||
} from '../helpers';
|
} from '../helpers/misc';
|
||||||
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
||||||
import { processMessageAndUpdateThreadInfo } from '../updates/entityProcessor';
|
import { processMessageAndUpdateThreadInfo } from '../updates/entityProcessor';
|
||||||
import { processAffectedHistory, updateChannelState } from '../updates/updateManager';
|
import { processAffectedHistory, updateChannelState } from '../updates/updateManager';
|
||||||
|
|||||||
@ -45,13 +45,15 @@ import {
|
|||||||
buildShippingInfo,
|
buildShippingInfo,
|
||||||
} from '../gramjsBuilders';
|
} from '../gramjsBuilders';
|
||||||
import {
|
import {
|
||||||
|
checkErrorType,
|
||||||
deserializeBytes,
|
deserializeBytes,
|
||||||
serializeBytes,
|
serializeBytes,
|
||||||
} from '../helpers';
|
wrapError,
|
||||||
|
} from '../helpers/misc';
|
||||||
import localDb from '../localDb';
|
import localDb from '../localDb';
|
||||||
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
||||||
import { handleGramJsUpdate, invokeRequest } from './client';
|
import { handleGramJsUpdate, invokeRequest } from './client';
|
||||||
import { getTemporaryPaymentPassword } from './twoFaSettings';
|
import { getPassword, getTemporaryPaymentPassword } from './twoFaSettings';
|
||||||
|
|
||||||
export async function validateRequestedInfo({
|
export async function validateRequestedInfo({
|
||||||
inputInvoice,
|
inputInvoice,
|
||||||
@ -689,3 +691,42 @@ export function upgradeGift({
|
|||||||
shouldReturnTrue: true,
|
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,
|
buildInputPrivacyKey,
|
||||||
buildInputPrivacyRules,
|
buildInputPrivacyRules,
|
||||||
} from '../gramjsBuilders';
|
} from '../gramjsBuilders';
|
||||||
import { addPhotoToLocalDb } from '../helpers';
|
import { addPhotoToLocalDb } from '../helpers/localDb';
|
||||||
import localDb from '../localDb';
|
import localDb from '../localDb';
|
||||||
import { getClient, invokeRequest, uploadFile } from './client';
|
import { getClient, invokeRequest, uploadFile } from './client';
|
||||||
|
|
||||||
|
|||||||
@ -16,8 +16,9 @@ import {
|
|||||||
buildStoryPublicForwards,
|
buildStoryPublicForwards,
|
||||||
} from '../apiBuilders/statistics';
|
} from '../apiBuilders/statistics';
|
||||||
import { buildInputEntity, buildInputPeer } from '../gramjsBuilders';
|
import { buildInputEntity, buildInputPeer } from '../gramjsBuilders';
|
||||||
|
import { checkErrorType, wrapError } from '../helpers/misc';
|
||||||
import { invokeRequest } from './client';
|
import { invokeRequest } from './client';
|
||||||
import { getPassword, onPasswordError } from './twoFaSettings';
|
import { getPassword } from './twoFaSettings';
|
||||||
|
|
||||||
export async function fetchChannelStatistics({
|
export async function fetchChannelStatistics({
|
||||||
chat, dcId,
|
chat, dcId,
|
||||||
@ -216,7 +217,7 @@ export async function fetchStoryPublicForwards({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadMonetizationRevenueWithdrawalUrl({
|
export async function fetchMonetizationRevenueWithdrawalUrl({
|
||||||
peer, currentPassword,
|
peer, currentPassword,
|
||||||
}: {
|
}: {
|
||||||
peer: ApiPeer;
|
peer: ApiPeer;
|
||||||
@ -225,10 +226,14 @@ export async function loadMonetizationRevenueWithdrawalUrl({
|
|||||||
try {
|
try {
|
||||||
const password = await getPassword(currentPassword);
|
const password = await getPassword(currentPassword);
|
||||||
|
|
||||||
if (!password || 'error' in password) {
|
if (!password) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('error' in password) {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
const result = await invokeRequest(new GramJs.stats.GetBroadcastRevenueWithdrawalUrl({
|
const result = await invokeRequest(new GramJs.stats.GetBroadcastRevenueWithdrawalUrl({
|
||||||
peer: buildInputPeer(peer.id, peer.accessHash),
|
peer: buildInputPeer(peer.id, peer.accessHash),
|
||||||
password,
|
password,
|
||||||
@ -240,9 +245,10 @@ export async function loadMonetizationRevenueWithdrawalUrl({
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return { url: result.url };
|
||||||
} catch (err: any) {
|
} catch (err: unknown) {
|
||||||
onPasswordError(err);
|
if (!checkErrorType(err)) return undefined;
|
||||||
|
return wrapError(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|||||||
@ -26,7 +26,8 @@ import {
|
|||||||
buildInputPrivacyRules,
|
buildInputPrivacyRules,
|
||||||
buildInputReaction,
|
buildInputReaction,
|
||||||
} from '../gramjsBuilders';
|
} from '../gramjsBuilders';
|
||||||
import { addStoryToLocalDb, deserializeBytes } from '../helpers';
|
import { addStoryToLocalDb } from '../helpers/localDb';
|
||||||
|
import { deserializeBytes } from '../helpers/misc';
|
||||||
import { invokeRequest } from './client';
|
import { invokeRequest } from './client';
|
||||||
|
|
||||||
export async function fetchAllStories({
|
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 { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
||||||
import {
|
import {
|
||||||
getCurrentPassword, getTmpPassword, invokeRequest, updateTwoFaSettings,
|
getCurrentPassword, getTmpPassword, invokeRequest, updateTwoFaSettings,
|
||||||
} from './client';
|
} 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: {
|
const emailCodeController: {
|
||||||
resolve?: Function;
|
resolve?: Function;
|
||||||
reject?: Function;
|
reject?: Function;
|
||||||
@ -45,18 +35,22 @@ function onRequestEmailCode(length: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getTemporaryPaymentPassword(password: string, ttl?: 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) {
|
export function getPassword(password: string) {
|
||||||
try {
|
try {
|
||||||
return getCurrentPassword({
|
return getCurrentPassword(password);
|
||||||
currentPassword: password,
|
} catch (err: unknown) {
|
||||||
onPasswordCodeError: onPasswordError,
|
if (!checkErrorType(err)) return undefined;
|
||||||
});
|
|
||||||
} catch (err: any) {
|
return Promise.resolve(wrapError(err));
|
||||||
onPasswordError(err);
|
|
||||||
return undefined;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,51 +120,10 @@ export function provideRecoveryEmailCode(code: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onError(err: Error) {
|
function onError(err: Error) {
|
||||||
let message: string;
|
const wrappedError = wrapError(err);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sendApiUpdate({
|
sendApiUpdate({
|
||||||
'@type': 'updateTwoFaError',
|
'@type': 'updateTwoFaError',
|
||||||
message,
|
messageKey: wrappedError.messageKey,
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import {
|
|||||||
buildMtpPeerId,
|
buildMtpPeerId,
|
||||||
getEntityTypeById,
|
getEntityTypeById,
|
||||||
} from '../gramjsBuilders';
|
} from '../gramjsBuilders';
|
||||||
import { addPhotoToLocalDb, addUserToLocalDb } from '../helpers';
|
import { addPhotoToLocalDb, addUserToLocalDb } from '../helpers/localDb';
|
||||||
import localDb from '../localDb';
|
import localDb from '../localDb';
|
||||||
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
|
||||||
import { invokeRequest } from './client';
|
import { invokeRequest } from './client';
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import { buildApiChatFromPreview } from '../apiBuilders/chats';
|
|||||||
import { buildPollFromMedia } from '../apiBuilders/messageContent';
|
import { buildPollFromMedia } from '../apiBuilders/messageContent';
|
||||||
import { buildApiThreadInfoFromMessage } from '../apiBuilders/messages';
|
import { buildApiThreadInfoFromMessage } from '../apiBuilders/messages';
|
||||||
import { buildApiUser } from '../apiBuilders/users';
|
import { buildApiUser } from '../apiBuilders/users';
|
||||||
import { addChatToLocalDb, addMessageToLocalDb, addUserToLocalDb } from '../helpers';
|
import { addChatToLocalDb, addMessageToLocalDb, addUserToLocalDb } from '../helpers/localDb';
|
||||||
import { sendImmediateApiUpdate } from './apiUpdateEmitter';
|
import { sendImmediateApiUpdate } from './apiUpdateEmitter';
|
||||||
|
|
||||||
const TYPE_USER = new Set(['User', 'UserEmpty']);
|
const TYPE_USER = new Set(['User', 'UserEmpty']);
|
||||||
|
|||||||
@ -71,11 +71,13 @@ import {
|
|||||||
import {
|
import {
|
||||||
addPhotoToLocalDb,
|
addPhotoToLocalDb,
|
||||||
addStoryToLocalDb,
|
addStoryToLocalDb,
|
||||||
|
} from '../helpers/localDb';
|
||||||
|
import {
|
||||||
isChatFolder,
|
isChatFolder,
|
||||||
log,
|
log,
|
||||||
resolveMessageApiChatId,
|
resolveMessageApiChatId,
|
||||||
serializeBytes,
|
serializeBytes,
|
||||||
} from '../helpers';
|
} from '../helpers/misc';
|
||||||
import localDb from '../localDb';
|
import localDb from '../localDb';
|
||||||
import { scheduleMutedChatUpdate, scheduleMutedTopicUpdate } from '../scheduleUnmute';
|
import { scheduleMutedChatUpdate, scheduleMutedTopicUpdate } from '../scheduleUnmute';
|
||||||
import { sendApiUpdate } from './apiUpdateEmitter';
|
import { sendApiUpdate } from './apiUpdateEmitter';
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import type { OriginMessageEvent, WorkerPayload } from './types';
|
|||||||
import { DEBUG } from '../../../config';
|
import { DEBUG } from '../../../config';
|
||||||
import { DEBUG_LEVELS } from '../../../util/debugConsole';
|
import { DEBUG_LEVELS } from '../../../util/debugConsole';
|
||||||
import { throttleWithTickEnd } from '../../../util/schedulers';
|
import { throttleWithTickEnd } from '../../../util/schedulers';
|
||||||
import { log } from '../helpers';
|
import { log } from '../helpers/misc';
|
||||||
import { callApi, cancelApiProgress, initApi } from '../methods/init';
|
import { callApi, cancelApiProgress, initApi } from '../methods/init';
|
||||||
|
|
||||||
declare const self: WorkerGlobalScope;
|
declare const self: WorkerGlobalScope;
|
||||||
|
|||||||
@ -271,6 +271,7 @@ export interface ApiSavedStarGift {
|
|||||||
canUpgrade?: true;
|
canUpgrade?: true;
|
||||||
alreadyPaidUpgradeStars?: number;
|
alreadyPaidUpgradeStars?: number;
|
||||||
transferStars?: number;
|
transferStars?: number;
|
||||||
|
canExportAt?: number;
|
||||||
isConverted?: boolean; // Local field, used for Action Message
|
isConverted?: boolean; // Local field, used for Action Message
|
||||||
upgradeMsgId?: number; // Local field, used for Action Message
|
upgradeMsgId?: number; // Local field, used for Action Message
|
||||||
}
|
}
|
||||||
|
|||||||
@ -491,12 +491,7 @@ export type ApiUpdateSavedGifs = {
|
|||||||
|
|
||||||
export type ApiUpdateTwoFaError = {
|
export type ApiUpdateTwoFaError = {
|
||||||
'@type': 'updateTwoFaError';
|
'@type': 'updateTwoFaError';
|
||||||
message: string;
|
messageKey: RegularLangFnParameters;
|
||||||
};
|
|
||||||
|
|
||||||
export type ApiUpdatePasswordError = {
|
|
||||||
'@type': 'updatePasswordError';
|
|
||||||
error: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ApiUpdateNotifySettings = {
|
export type ApiUpdateNotifySettings = {
|
||||||
@ -819,7 +814,7 @@ export type ApiUpdate = (
|
|||||||
ApiUpdateRecentStickers | ApiUpdateSavedGifs | ApiUpdateNewScheduledMessage | ApiUpdateMoveStickerSetToTop |
|
ApiUpdateRecentStickers | ApiUpdateSavedGifs | ApiUpdateNewScheduledMessage | ApiUpdateMoveStickerSetToTop |
|
||||||
ApiUpdateScheduledMessageSendSucceeded | ApiUpdateScheduledMessage | ApiUpdateStarPaymentStateCompleted |
|
ApiUpdateScheduledMessageSendSucceeded | ApiUpdateScheduledMessage | ApiUpdateStarPaymentStateCompleted |
|
||||||
ApiUpdateDeleteScheduledMessages | ApiUpdateResetMessages | ApiUpdateMessageTranslations |
|
ApiUpdateDeleteScheduledMessages | ApiUpdateResetMessages | ApiUpdateMessageTranslations |
|
||||||
ApiUpdateTwoFaError | ApiUpdatePasswordError | ApiUpdateTwoFaStateWaitCode | ApiUpdateWebViewResultSent |
|
ApiUpdateTwoFaError | ApiUpdateTwoFaStateWaitCode | ApiUpdateWebViewResultSent |
|
||||||
ApiUpdateNotifySettings | ApiUpdateNotifyExceptions | ApiUpdatePeerBlocked | ApiUpdatePrivacy |
|
ApiUpdateNotifySettings | ApiUpdateNotifyExceptions | ApiUpdatePeerBlocked | ApiUpdatePrivacy |
|
||||||
ApiUpdateServerTimeOffset | ApiUpdateMessageReactions | ApiUpdateSavedReactionTags |
|
ApiUpdateServerTimeOffset | ApiUpdateMessageReactions | ApiUpdateSavedReactionTags |
|
||||||
ApiUpdateGroupCallParticipants | ApiUpdateGroupCallConnection | ApiUpdateGroupCall | ApiUpdateGroupCallStreams |
|
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";
|
"FavoriteStickers" = "Favorites";
|
||||||
"PremiumStickers" = "Premium Stickers";
|
"PremiumStickers" = "Premium Stickers";
|
||||||
"GroupStickers" = "Group Stickers";
|
"GroupStickers" = "Group Stickers";
|
||||||
"ErrorSendRestrictedStickersAll" = "Sorry, sending stickers is not allowed in this group.";
|
"ErrorSendRestrictedStickersAll" = "Sorry, sending stickers is not allowed in this group";
|
||||||
"ErrorPhoneNumberInvalid" = "Invalid phone number, please try again.";
|
"ErrorPhoneNumberInvalid" = "Invalid phone number, please try again";
|
||||||
"ErrorCodeInvalid" = "Invalid code, please try again.";
|
"ErrorCodeInvalid" = "Invalid code, please try again";
|
||||||
"ErrorIncorrectPassword" = "Invalid password, please try again.";
|
"ErrorEmailCodeInvalid" = "Invalid code, please try again";
|
||||||
"ErrorPasswordFlood" = "Too many attempts, please try again later.";
|
"ErrorIncorrectPassword" = "Invalid password, please try again";
|
||||||
"ErrorPhoneBanned" = "This phone number is banned.";
|
"ErrorPasswordFlood" = "Too many attempts, please try again later";
|
||||||
"ErrorFlood_one" = "Too many attempts, please try again in {hour} hour";
|
"ErrorPhoneBanned" = "This phone number is banned";
|
||||||
"ErrorFlood_other" = "Too many attempts, please try again in {hour} hours";
|
"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";
|
"ErrorUnexpected" = "Unexpected error";
|
||||||
"ErrorUnexpectedMessage" = "Unexpected error: {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";
|
"NoStickers" = "No stickers yet";
|
||||||
"ClearRecentEmoji" = "Clear recent emoji?";
|
"ClearRecentEmoji" = "Clear recent emoji?";
|
||||||
"TextFormatAddLinkTitle" = "Add Link";
|
"TextFormatAddLinkTitle" = "Add Link";
|
||||||
@ -1429,6 +1436,7 @@
|
|||||||
"GiftInfoViewUpgraded" = "View Upgraded Gift";
|
"GiftInfoViewUpgraded" = "View Upgraded Gift";
|
||||||
"GiftInfoUpgradeBadge" = "upgrade";
|
"GiftInfoUpgradeBadge" = "upgrade";
|
||||||
"GiftInfoUpgradeForFree" = "Upgrade For Free";
|
"GiftInfoUpgradeForFree" = "Upgrade For Free";
|
||||||
|
"GiftInfoWithdraw" = "Withdraw";
|
||||||
"GiftUpgradeUniqueTitle" = "Unique";
|
"GiftUpgradeUniqueTitle" = "Unique";
|
||||||
"GiftUpgradeUniqueDescription" = "Turn your gift into a unique collectible that you can transfer or auction.";
|
"GiftUpgradeUniqueDescription" = "Turn your gift into a unique collectible that you can transfer or auction.";
|
||||||
"GiftUpgradeTransferableTitle" = "Transferable";
|
"GiftUpgradeTransferableTitle" = "Transferable";
|
||||||
@ -1447,6 +1455,11 @@
|
|||||||
"GiftMakeUniqueDescription" = "Enable this to let {user} turn your gift into a unique collectible. {link}";
|
"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}";
|
"GiftMakeUniqueDescriptionChannel" = "Enable this to let admins of {peer} to turn your gift into a unique collectible. {link}";
|
||||||
"GiftMakeUniqueLink" = "Learn More >";
|
"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}";
|
"StarsAmount" = "⭐️{amount}";
|
||||||
"StarsAmountText_one" = "{amount} Star";
|
"StarsAmountText_one" = "{amount} Star";
|
||||||
"StarsAmountText_other" = "{amount} Stars";
|
"StarsAmountText_other" = "{amount} Stars";
|
||||||
@ -1586,3 +1599,6 @@
|
|||||||
"ViewButtonGiftUnique" = "VIEW COLLECTIBLE";
|
"ViewButtonGiftUnique" = "VIEW COLLECTIBLE";
|
||||||
"AuthContinueOnThisLanguage" = "Continue in English";
|
"AuthContinueOnThisLanguage" = "Continue in English";
|
||||||
"Share" = "Share";
|
"Share" = "Share";
|
||||||
|
"CheckPasswordTitle" = "Enter Password";
|
||||||
|
"CheckPasswordPlaceholder" = "Password";
|
||||||
|
"CheckPasswordDescription" = "Please enter your password to continue.";
|
||||||
|
|||||||
@ -28,7 +28,7 @@ const INITIAL_KEYS: LangKey[] = [
|
|||||||
'ErrorIncorrectPassword',
|
'ErrorIncorrectPassword',
|
||||||
'ErrorPasswordFlood',
|
'ErrorPasswordFlood',
|
||||||
'ErrorPhoneBanned',
|
'ErrorPhoneBanned',
|
||||||
'ErrorFlood',
|
'ErrorFloodTime',
|
||||||
'ErrorUnexpected',
|
'ErrorUnexpected',
|
||||||
'ErrorUnexpectedMessage',
|
'ErrorUnexpectedMessage',
|
||||||
];
|
];
|
||||||
|
|||||||
@ -31,10 +31,7 @@ export default {
|
|||||||
"ErrorIncorrectPassword": "Invalid password, please try again.",
|
"ErrorIncorrectPassword": "Invalid password, please try again.",
|
||||||
"ErrorPasswordFlood": "Too many attempts, please try again later.",
|
"ErrorPasswordFlood": "Too many attempts, please try again later.",
|
||||||
"ErrorPhoneBanned": "This phone number is banned.",
|
"ErrorPhoneBanned": "This phone number is banned.",
|
||||||
"ErrorFlood": {
|
"ErrorFloodTime": "Too many attempts, please try again in {time}.",
|
||||||
"one": "Too many attempts, please try again in {hour} hour",
|
|
||||||
"other": "Too many attempts, please try again in {hour} hours"
|
|
||||||
},
|
|
||||||
"ErrorUnexpected": "Unexpected error",
|
"ErrorUnexpected": "Unexpected error",
|
||||||
"ErrorUnexpectedMessage": "Unexpected error: {error}"
|
"ErrorUnexpectedMessage": "Unexpected error: {error}"
|
||||||
} as Record<LangKey, LangPackStringValue>;
|
} 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 GiftRecipientPicker } from '../components/modals/gift/recipient/GiftRecipientPicker';
|
||||||
export { default as GiftInfoModal } from '../components/modals/gift/info/GiftInfoModal';
|
export { default as GiftInfoModal } from '../components/modals/gift/info/GiftInfoModal';
|
||||||
export { default as GiftUpgradeModal } from '../components/modals/gift/upgrade/GiftUpgradeModal';
|
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';
|
import useModuleLoader from '../../hooks/useModuleLoader';
|
||||||
|
|
||||||
const VerificationMonetizationModalAsync: FC<OwnProps> = (props) => {
|
const VerificationMonetizationModalAsync: FC<OwnProps> = (props) => {
|
||||||
const { isOpen } = props;
|
const { modal } = props;
|
||||||
const VerificationMonetizationModal = useModuleLoader(Bundles.Extra, 'VerificationMonetizationModal', !isOpen);
|
const VerificationMonetizationModal = useModuleLoader(Bundles.Extra, 'VerificationMonetizationModal', !modal);
|
||||||
|
|
||||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||||
return VerificationMonetizationModal ? <VerificationMonetizationModal {...props} /> : undefined;
|
return VerificationMonetizationModal ? <VerificationMonetizationModal {...props} /> : undefined;
|
||||||
|
|||||||
@ -1,14 +1,16 @@
|
|||||||
import type { FC } from '../../lib/teact/teact';
|
|
||||||
import React, {
|
import React, {
|
||||||
memo,
|
memo,
|
||||||
useState,
|
useState,
|
||||||
} from '../../lib/teact/teact';
|
} 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 buildClassName from '../../util/buildClassName';
|
||||||
|
|
||||||
|
import useCurrentOrPrev from '../../hooks/useCurrentOrPrev';
|
||||||
|
import useLang from '../../hooks/useLang';
|
||||||
import useLastCallback from '../../hooks/useLastCallback';
|
import useLastCallback from '../../hooks/useLastCallback';
|
||||||
import useOldLang from '../../hooks/useOldLang';
|
|
||||||
|
|
||||||
import Modal from '../ui/Modal';
|
import Modal from '../ui/Modal';
|
||||||
import PasswordForm from './PasswordForm';
|
import PasswordForm from './PasswordForm';
|
||||||
@ -16,62 +18,63 @@ import PasswordForm from './PasswordForm';
|
|||||||
import styles from './VerificationMonetizationModal.module.scss';
|
import styles from './VerificationMonetizationModal.module.scss';
|
||||||
|
|
||||||
export type OwnProps = {
|
export type OwnProps = {
|
||||||
isOpen: boolean;
|
modal: TabState['monetizationVerificationModal'];
|
||||||
onClose: NoneToVoidFunction;
|
|
||||||
chatId: string;
|
|
||||||
passwordHint?: string;
|
|
||||||
error?: string;
|
|
||||||
isLoading?: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const VerificationMonetizationModal: FC<OwnProps> = ({
|
type StateProps = {
|
||||||
isOpen,
|
passwordHint?: string;
|
||||||
chatId,
|
};
|
||||||
onClose,
|
|
||||||
|
const VerificationMonetizationModal = ({
|
||||||
|
modal,
|
||||||
passwordHint,
|
passwordHint,
|
||||||
error,
|
}: OwnProps & StateProps) => {
|
||||||
isLoading,
|
|
||||||
}) => {
|
|
||||||
const {
|
const {
|
||||||
clearMonetizationInfo, loadMonetizationRevenueWithdrawalUrl,
|
closeMonetizationVerificationModal, clearMonetizationVerificationError, processMonetizationRevenueWithdrawalUrl,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
const lang = useOldLang();
|
const isOpen = Boolean(modal);
|
||||||
|
|
||||||
|
const renderingModal = useCurrentOrPrev(modal);
|
||||||
|
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
const [shouldShowPassword, setShouldShowPassword] = useState(false);
|
const [shouldShowPassword, setShouldShowPassword] = useState(false);
|
||||||
|
|
||||||
const handleSubmit = useLastCallback((password: string) => {
|
const handleSubmit = useLastCallback((password: string) => {
|
||||||
loadMonetizationRevenueWithdrawalUrl({
|
if (!renderingModal) return;
|
||||||
peerId: chatId,
|
processMonetizationRevenueWithdrawalUrl({
|
||||||
|
peerId: renderingModal.chatId,
|
||||||
currentPassword: password,
|
currentPassword: password,
|
||||||
onSuccess: () => {
|
|
||||||
onClose();
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleClearError = useLastCallback(() => {
|
const handleClearError = useLastCallback(() => {
|
||||||
clearMonetizationInfo();
|
clearMonetizationVerificationError();
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleClose = useLastCallback(() => {
|
||||||
|
closeMonetizationVerificationModal();
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
hasCloseButton
|
hasCloseButton
|
||||||
title={lang('EnterPassword')}
|
title={lang('CheckPasswordTitle')}
|
||||||
className={styles.root}
|
className={styles.root}
|
||||||
contentClassName={styles.content}
|
contentClassName={styles.content}
|
||||||
onClose={onClose}
|
onClose={handleClose}
|
||||||
>
|
>
|
||||||
<div className={buildClassName(styles.content, 'settings-content password-form custom-scroll')}>
|
<div className={buildClassName(styles.content, 'settings-content password-form custom-scroll')}>
|
||||||
<div className="settings-item pt-0">
|
<div className="settings-item pt-0">
|
||||||
<PasswordForm
|
<PasswordForm
|
||||||
shouldShowSubmit
|
shouldShowSubmit
|
||||||
placeholder={lang('Password')}
|
placeholder={lang('CheckPasswordPlaceholder')}
|
||||||
error={error && lang(error)}
|
error={renderingModal?.errorKey && lang.withRegular(renderingModal.errorKey)}
|
||||||
description={lang('Channel.OwnershipTransfer.EnterPasswordText')}
|
description={lang('CheckPasswordDescription')}
|
||||||
clearError={handleClearError}
|
clearError={handleClearError}
|
||||||
isLoading={isLoading}
|
isLoading={renderingModal?.isLoading}
|
||||||
hint={passwordHint}
|
hint={passwordHint}
|
||||||
isPasswordVisible={shouldShowPassword}
|
isPasswordVisible={shouldShowPassword}
|
||||||
shouldResetValue={isOpen}
|
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 type { TwoFaDispatch, TwoFaState } from '../../../../hooks/reducers/useTwoFaReducer';
|
||||||
import { SettingsScreens } from '../../../../types';
|
import { SettingsScreens } from '../../../../types';
|
||||||
|
|
||||||
|
import useLang from '../../../../hooks/useLang';
|
||||||
import useOldLang from '../../../../hooks/useOldLang';
|
import useOldLang from '../../../../hooks/useOldLang';
|
||||||
|
|
||||||
import SettingsTwoFaPassword from '../SettingsPasswordForm';
|
import SettingsTwoFaPassword from '../SettingsPasswordForm';
|
||||||
@ -33,7 +34,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
|||||||
state,
|
state,
|
||||||
hint,
|
hint,
|
||||||
isLoading,
|
isLoading,
|
||||||
error,
|
errorKey,
|
||||||
waitingEmailCodeLength,
|
waitingEmailCodeLength,
|
||||||
dispatch,
|
dispatch,
|
||||||
isActive,
|
isActive,
|
||||||
@ -49,6 +50,9 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
|||||||
clearPassword,
|
clearPassword,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
|
const lang = useLang();
|
||||||
|
const oldLang = useOldLang();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (waitingEmailCodeLength) {
|
if (waitingEmailCodeLength) {
|
||||||
if (currentScreen === SettingsScreens.TwoFaNewPasswordEmail) {
|
if (currentScreen === SettingsScreens.TwoFaNewPasswordEmail) {
|
||||||
@ -153,8 +157,6 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
|||||||
provideTwoFaEmailCode({ code });
|
provideTwoFaEmailCode({ code });
|
||||||
}, [provideTwoFaEmailCode]);
|
}, [provideTwoFaEmailCode]);
|
||||||
|
|
||||||
const lang = useOldLang();
|
|
||||||
|
|
||||||
switch (currentScreen) {
|
switch (currentScreen) {
|
||||||
case SettingsScreens.TwoFaDisabled:
|
case SettingsScreens.TwoFaDisabled:
|
||||||
return (
|
return (
|
||||||
@ -175,8 +177,8 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
|||||||
case SettingsScreens.TwoFaNewPassword:
|
case SettingsScreens.TwoFaNewPassword:
|
||||||
return (
|
return (
|
||||||
<SettingsTwoFaPassword
|
<SettingsTwoFaPassword
|
||||||
placeholder={lang('PleaseEnterPassword')}
|
placeholder={oldLang('PleaseEnterPassword')}
|
||||||
submitLabel={lang('Continue')}
|
submitLabel={oldLang('Continue')}
|
||||||
onSubmit={handleNewPassword}
|
onSubmit={handleNewPassword}
|
||||||
isActive={isActive || [
|
isActive={isActive || [
|
||||||
SettingsScreens.TwoFaNewPasswordConfirm,
|
SettingsScreens.TwoFaNewPasswordConfirm,
|
||||||
@ -193,8 +195,8 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
|||||||
return (
|
return (
|
||||||
<SettingsTwoFaPassword
|
<SettingsTwoFaPassword
|
||||||
expectedPassword={state.password}
|
expectedPassword={state.password}
|
||||||
placeholder={lang('PleaseReEnterPassword')}
|
placeholder={oldLang('PleaseReEnterPassword')}
|
||||||
submitLabel={lang('Continue')}
|
submitLabel={oldLang('Continue')}
|
||||||
onSubmit={handleNewPasswordConfirm}
|
onSubmit={handleNewPasswordConfirm}
|
||||||
isActive={isActive || [
|
isActive={isActive || [
|
||||||
SettingsScreens.TwoFaNewPasswordHint,
|
SettingsScreens.TwoFaNewPasswordHint,
|
||||||
@ -210,7 +212,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
|||||||
return (
|
return (
|
||||||
<SettingsTwoFaSkippableForm
|
<SettingsTwoFaSkippableForm
|
||||||
icon="hint"
|
icon="hint"
|
||||||
placeholder={lang('PasswordHintPlaceholder')}
|
placeholder={oldLang('PasswordHintPlaceholder')}
|
||||||
onSubmit={handleNewPasswordHint}
|
onSubmit={handleNewPasswordHint}
|
||||||
isActive={isActive || [
|
isActive={isActive || [
|
||||||
SettingsScreens.TwoFaNewPasswordEmail,
|
SettingsScreens.TwoFaNewPasswordEmail,
|
||||||
@ -227,9 +229,9 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
|||||||
icon="email"
|
icon="email"
|
||||||
type="email"
|
type="email"
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
error={error}
|
error={errorKey && lang.withRegular(errorKey)}
|
||||||
clearError={clearTwoFaError}
|
clearError={clearTwoFaError}
|
||||||
placeholder={lang('RecoveryEmailTitle')}
|
placeholder={oldLang('RecoveryEmailTitle')}
|
||||||
shouldConfirm
|
shouldConfirm
|
||||||
onSubmit={handleNewPasswordEmail}
|
onSubmit={handleNewPasswordEmail}
|
||||||
isActive={isActive || [
|
isActive={isActive || [
|
||||||
@ -244,7 +246,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
|||||||
return (
|
return (
|
||||||
<SettingsTwoFaEmailCode
|
<SettingsTwoFaEmailCode
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
error={error}
|
error={errorKey && lang.withRegular(errorKey)}
|
||||||
clearError={clearTwoFaError}
|
clearError={clearTwoFaError}
|
||||||
onSubmit={handleEmailCode}
|
onSubmit={handleEmailCode}
|
||||||
isActive={isActive || shownScreen === SettingsScreens.TwoFaCongratulations}
|
isActive={isActive || shownScreen === SettingsScreens.TwoFaCongratulations}
|
||||||
@ -284,7 +286,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
|||||||
return (
|
return (
|
||||||
<SettingsTwoFaPassword
|
<SettingsTwoFaPassword
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
error={error}
|
error={errorKey && lang.withRegular(errorKey)}
|
||||||
clearError={clearTwoFaError}
|
clearError={clearTwoFaError}
|
||||||
hint={hint}
|
hint={hint}
|
||||||
onSubmit={handleChangePasswordCurrent}
|
onSubmit={handleChangePasswordCurrent}
|
||||||
@ -301,7 +303,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
|||||||
case SettingsScreens.TwoFaChangePasswordNew:
|
case SettingsScreens.TwoFaChangePasswordNew:
|
||||||
return (
|
return (
|
||||||
<SettingsTwoFaPassword
|
<SettingsTwoFaPassword
|
||||||
placeholder={lang('PleaseEnterNewFirstPassword')}
|
placeholder={oldLang('PleaseEnterNewFirstPassword')}
|
||||||
onSubmit={handleChangePasswordNew}
|
onSubmit={handleChangePasswordNew}
|
||||||
isActive={isActive || [
|
isActive={isActive || [
|
||||||
SettingsScreens.TwoFaChangePasswordConfirm,
|
SettingsScreens.TwoFaChangePasswordConfirm,
|
||||||
@ -316,7 +318,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
|||||||
return (
|
return (
|
||||||
<SettingsTwoFaPassword
|
<SettingsTwoFaPassword
|
||||||
expectedPassword={state.password}
|
expectedPassword={state.password}
|
||||||
placeholder={lang('PleaseReEnterPassword')}
|
placeholder={oldLang('PleaseReEnterPassword')}
|
||||||
onSubmit={handleChangePasswordConfirm}
|
onSubmit={handleChangePasswordConfirm}
|
||||||
isActive={isActive || [
|
isActive={isActive || [
|
||||||
SettingsScreens.TwoFaChangePasswordHint,
|
SettingsScreens.TwoFaChangePasswordHint,
|
||||||
@ -330,10 +332,10 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
|||||||
return (
|
return (
|
||||||
<SettingsTwoFaSkippableForm
|
<SettingsTwoFaSkippableForm
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
error={error}
|
error={errorKey && lang.withRegular(errorKey)}
|
||||||
clearError={clearTwoFaError}
|
clearError={clearTwoFaError}
|
||||||
icon="hint"
|
icon="hint"
|
||||||
placeholder={lang('PasswordHintPlaceholder')}
|
placeholder={oldLang('PasswordHintPlaceholder')}
|
||||||
onSubmit={handleChangePasswordHint}
|
onSubmit={handleChangePasswordHint}
|
||||||
isActive={isActive || shownScreen === SettingsScreens.TwoFaCongratulations}
|
isActive={isActive || shownScreen === SettingsScreens.TwoFaCongratulations}
|
||||||
onReset={onReset}
|
onReset={onReset}
|
||||||
@ -344,7 +346,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
|||||||
return (
|
return (
|
||||||
<SettingsTwoFaPassword
|
<SettingsTwoFaPassword
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
error={error}
|
error={errorKey && lang.withRegular(errorKey)}
|
||||||
clearError={clearTwoFaError}
|
clearError={clearTwoFaError}
|
||||||
hint={hint}
|
hint={hint}
|
||||||
onSubmit={handleTurnOff}
|
onSubmit={handleTurnOff}
|
||||||
@ -357,7 +359,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
|||||||
return (
|
return (
|
||||||
<SettingsTwoFaPassword
|
<SettingsTwoFaPassword
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
error={error}
|
error={errorKey && lang.withRegular(errorKey)}
|
||||||
clearError={clearTwoFaError}
|
clearError={clearTwoFaError}
|
||||||
hint={hint}
|
hint={hint}
|
||||||
onSubmit={handleRecoveryEmailCurrentPassword}
|
onSubmit={handleRecoveryEmailCurrentPassword}
|
||||||
@ -375,7 +377,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
|||||||
<SettingsTwoFaSkippableForm
|
<SettingsTwoFaSkippableForm
|
||||||
icon="email"
|
icon="email"
|
||||||
type="email"
|
type="email"
|
||||||
placeholder={lang('RecoveryEmailTitle')}
|
placeholder={oldLang('RecoveryEmailTitle')}
|
||||||
onSubmit={handleRecoveryEmail}
|
onSubmit={handleRecoveryEmail}
|
||||||
isActive={isActive || [
|
isActive={isActive || [
|
||||||
SettingsScreens.TwoFaRecoveryEmailCode,
|
SettingsScreens.TwoFaRecoveryEmailCode,
|
||||||
@ -389,7 +391,7 @@ const SettingsTwoFa: FC<OwnProps & StateProps> = ({
|
|||||||
return (
|
return (
|
||||||
<SettingsTwoFaEmailCode
|
<SettingsTwoFaEmailCode
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
error={error}
|
error={errorKey && lang.withRegular(errorKey)}
|
||||||
clearError={clearTwoFaError}
|
clearError={clearTwoFaError}
|
||||||
onSubmit={handleEmailCode}
|
onSubmit={handleEmailCode}
|
||||||
isActive={isActive || shownScreen === SettingsScreens.TwoFaCongratulations}
|
isActive={isActive || shownScreen === SettingsScreens.TwoFaCongratulations}
|
||||||
|
|||||||
@ -245,6 +245,7 @@ const Main = ({
|
|||||||
loadAvailableEffects,
|
loadAvailableEffects,
|
||||||
loadTopBotApps,
|
loadTopBotApps,
|
||||||
loadPaidReactionPrivacy,
|
loadPaidReactionPrivacy,
|
||||||
|
loadPasswordInfo,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
if (DEBUG && !DEBUG_isLogged) {
|
if (DEBUG && !DEBUG_isLogged) {
|
||||||
@ -333,6 +334,7 @@ const Main = ({
|
|||||||
loadAuthorizations();
|
loadAuthorizations();
|
||||||
loadTopBotApps();
|
loadTopBotApps();
|
||||||
loadPaidReactionPrivacy();
|
loadPaidReactionPrivacy();
|
||||||
|
loadPasswordInfo();
|
||||||
}
|
}
|
||||||
}, [isMasterTab, isSynced]);
|
}, [isMasterTab, isSynced]);
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import type { TabState } from '../../global/types';
|
|||||||
import { selectTabState } from '../../global/selectors';
|
import { selectTabState } from '../../global/selectors';
|
||||||
import { pick } from '../../util/iteratees';
|
import { pick } from '../../util/iteratees';
|
||||||
|
|
||||||
|
import VerificationMonetizationModal from '../common/VerificationMonetizationModal.async';
|
||||||
import WebAppsCloseConfirmationModal from '../main/WebAppsCloseConfirmationModal.async';
|
import WebAppsCloseConfirmationModal from '../main/WebAppsCloseConfirmationModal.async';
|
||||||
import AboutAdsModal from './aboutAds/AboutAdsModal.async';
|
import AboutAdsModal from './aboutAds/AboutAdsModal.async';
|
||||||
import AttachBotInstallModal from './attachBotInstall/AttachBotInstallModal.async';
|
import AttachBotInstallModal from './attachBotInstall/AttachBotInstallModal.async';
|
||||||
@ -14,6 +15,7 @@ import ChatInviteModal from './chatInvite/ChatInviteModal.async';
|
|||||||
import ChatlistModal from './chatlist/ChatlistModal.async';
|
import ChatlistModal from './chatlist/ChatlistModal.async';
|
||||||
import CollectibleInfoModal from './collectible/CollectibleInfoModal.async';
|
import CollectibleInfoModal from './collectible/CollectibleInfoModal.async';
|
||||||
import EmojiStatusAccessModal from './emojiStatusAccess/EmojiStatusAccessModal.async';
|
import EmojiStatusAccessModal from './emojiStatusAccess/EmojiStatusAccessModal.async';
|
||||||
|
import GiftWithdrawModal from './gift/fragment/GiftWithdrawModal.async';
|
||||||
import PremiumGiftModal from './gift/GiftModal.async';
|
import PremiumGiftModal from './gift/GiftModal.async';
|
||||||
import GiftInfoModal from './gift/info/GiftInfoModal.async';
|
import GiftInfoModal from './gift/info/GiftInfoModal.async';
|
||||||
import GiftRecipientPicker from './gift/recipient/GiftRecipientPicker.async';
|
import GiftRecipientPicker from './gift/recipient/GiftRecipientPicker.async';
|
||||||
@ -65,7 +67,9 @@ type ModalKey = keyof Pick<TabState,
|
|||||||
'emojiStatusAccessModal' |
|
'emojiStatusAccessModal' |
|
||||||
'locationAccessModal' |
|
'locationAccessModal' |
|
||||||
'aboutAdsModal' |
|
'aboutAdsModal' |
|
||||||
'giftUpgradeModal'
|
'giftUpgradeModal' |
|
||||||
|
'monetizationVerificationModal' |
|
||||||
|
'giftWithdrawModal'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
@ -109,6 +113,8 @@ const MODALS: ModalRegistry = {
|
|||||||
locationAccessModal: LocationAccessModal,
|
locationAccessModal: LocationAccessModal,
|
||||||
aboutAdsModal: AboutAdsModal,
|
aboutAdsModal: AboutAdsModal,
|
||||||
giftUpgradeModal: GiftUpgradeModal,
|
giftUpgradeModal: GiftUpgradeModal,
|
||||||
|
monetizationVerificationModal: VerificationMonetizationModal,
|
||||||
|
giftWithdrawModal: GiftWithdrawModal,
|
||||||
};
|
};
|
||||||
const MODAL_KEYS = Object.keys(MODALS) as ModalKey[];
|
const MODAL_KEYS = Object.keys(MODALS) as ModalKey[];
|
||||||
const MODAL_ENTRIES = Object.entries(MODALS) as Entries<ModalRegistry>;
|
const MODAL_ENTRIES = Object.entries(MODALS) as Entries<ModalRegistry>;
|
||||||
|
|||||||
@ -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,
|
openGiftUpgradeModal,
|
||||||
showNotification,
|
showNotification,
|
||||||
openChatWithDraft,
|
openChatWithDraft,
|
||||||
|
openGiftWithdrawModal,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
const [isConvertConfirmOpen, openConvertConfirm, closeConvertConfirm] = useFlag();
|
const [isConvertConfirmOpen, openConvertConfirm, closeConvertConfirm] = useFlag();
|
||||||
@ -127,6 +128,11 @@ const GiftInfoModal = ({
|
|||||||
handleClose();
|
handleClose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleWithdraw = useLastCallback(() => {
|
||||||
|
if (savedGift?.gift.type !== 'starGiftUnique') return;
|
||||||
|
openGiftWithdrawModal({ gift: savedGift });
|
||||||
|
});
|
||||||
|
|
||||||
const handleFocusUpgraded = useLastCallback(() => {
|
const handleFocusUpgraded = useLastCallback(() => {
|
||||||
if (!savedGift?.upgradeMsgId || !renderingTargetPeer) return;
|
if (!savedGift?.upgradeMsgId || !renderingTargetPeer) return;
|
||||||
const { upgradeMsgId } = savedGift;
|
const { upgradeMsgId } = savedGift;
|
||||||
@ -291,6 +297,11 @@ const GiftInfoModal = ({
|
|||||||
>
|
>
|
||||||
{lang('Share')}
|
{lang('Share')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
{canUpdate && isUniqueGift && (
|
||||||
|
<MenuItem icon="diamond" onClick={handleWithdraw}>
|
||||||
|
{lang('GiftInfoWithdraw')}
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -4,9 +4,11 @@ import { getActions, withGlobal } from '../../global';
|
|||||||
|
|
||||||
import type { ApiPaymentCredentials } from '../../api/types';
|
import type { ApiPaymentCredentials } from '../../api/types';
|
||||||
import type { FormState } from '../../hooks/reducers/usePaymentReducer';
|
import type { FormState } from '../../hooks/reducers/usePaymentReducer';
|
||||||
|
import type { RegularLangFnParameters } from '../../util/localization';
|
||||||
|
|
||||||
import { selectTabState } from '../../global/selectors';
|
import { selectTabState } from '../../global/selectors';
|
||||||
|
|
||||||
|
import useLang from '../../hooks/useLang';
|
||||||
import useOldLang from '../../hooks/useOldLang';
|
import useOldLang from '../../hooks/useOldLang';
|
||||||
|
|
||||||
import PasswordForm from '../common/PasswordForm';
|
import PasswordForm from '../common/PasswordForm';
|
||||||
@ -20,14 +22,14 @@ interface OwnProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface StateProps {
|
interface StateProps {
|
||||||
error?: string;
|
errorKey?: RegularLangFnParameters;
|
||||||
passwordHint?: string;
|
passwordHint?: string;
|
||||||
savedCredentials?: ApiPaymentCredentials[];
|
savedCredentials?: ApiPaymentCredentials[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const PasswordConfirm: FC<OwnProps & StateProps> = ({
|
const PasswordConfirm: FC<OwnProps & StateProps> = ({
|
||||||
isActive,
|
isActive,
|
||||||
error,
|
errorKey,
|
||||||
state,
|
state,
|
||||||
savedCredentials,
|
savedCredentials,
|
||||||
passwordHint,
|
passwordHint,
|
||||||
@ -35,7 +37,9 @@ const PasswordConfirm: FC<OwnProps & StateProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { clearPaymentError } = getActions();
|
const { clearPaymentError } = getActions();
|
||||||
|
|
||||||
const lang = useOldLang();
|
const oldLang = useOldLang();
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
const [shouldShowPassword, setShouldShowPassword] = useState(false);
|
const [shouldShowPassword, setShouldShowPassword] = useState(false);
|
||||||
const cardName = useMemo(() => {
|
const cardName = useMemo(() => {
|
||||||
return savedCredentials?.length && state.savedCredentialId
|
return savedCredentials?.length && state.savedCredentialId
|
||||||
@ -48,10 +52,10 @@ const PasswordConfirm: FC<OwnProps & StateProps> = ({
|
|||||||
<PasswordMonkey isBig isPasswordVisible={shouldShowPassword} />
|
<PasswordMonkey isBig isPasswordVisible={shouldShowPassword} />
|
||||||
|
|
||||||
<PasswordForm
|
<PasswordForm
|
||||||
error={error ? lang(error) : undefined}
|
error={errorKey && lang.withRegular(errorKey)}
|
||||||
hint={passwordHint}
|
hint={passwordHint}
|
||||||
description={lang('PaymentConfirmationMessage', cardName)}
|
description={oldLang('PaymentConfirmationMessage', cardName)}
|
||||||
placeholder={lang('Password')}
|
placeholder={oldLang('Password')}
|
||||||
clearError={clearPaymentError}
|
clearError={clearPaymentError}
|
||||||
shouldShowSubmit={false}
|
shouldShowSubmit={false}
|
||||||
shouldResetValue={isActive}
|
shouldResetValue={isActive}
|
||||||
@ -66,7 +70,7 @@ const PasswordConfirm: FC<OwnProps & StateProps> = ({
|
|||||||
export default memo(withGlobal<OwnProps>((global): StateProps => {
|
export default memo(withGlobal<OwnProps>((global): StateProps => {
|
||||||
const { payment } = selectTabState(global);
|
const { payment } = selectTabState(global);
|
||||||
return {
|
return {
|
||||||
error: payment.error?.message,
|
errorKey: payment.error?.messageKey,
|
||||||
passwordHint: global.twoFaSettings.hint,
|
passwordHint: global.twoFaSettings.hint,
|
||||||
savedCredentials: payment.form?.type === 'regular' ? payment.form.savedCredentials : undefined,
|
savedCredentials: payment.form?.type === 'regular' ? payment.form.savedCredentials : undefined,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import React, {
|
|||||||
import type { ApiCountry } from '../../api/types';
|
import type { ApiCountry } from '../../api/types';
|
||||||
import type { FormEditDispatch, FormState } from '../../hooks/reducers/usePaymentReducer';
|
import type { FormEditDispatch, FormState } from '../../hooks/reducers/usePaymentReducer';
|
||||||
|
|
||||||
|
import useLang from '../../hooks/useLang';
|
||||||
import useOldLang from '../../hooks/useOldLang';
|
import useOldLang from '../../hooks/useOldLang';
|
||||||
|
|
||||||
import Checkbox from '../ui/Checkbox';
|
import Checkbox from '../ui/Checkbox';
|
||||||
@ -75,58 +76,59 @@ const PaymentInfo: FC<OwnProps> = ({
|
|||||||
dispatch({ type: 'changeSaveCredentials', payload: e.target.value });
|
dispatch({ type: 'changeSaveCredentials', payload: e.target.value });
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
const lang = useOldLang();
|
const oldLang = useOldLang();
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
const { formErrors = {} } = state;
|
const { formErrors = {} } = state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="PaymentInfo">
|
<div className="PaymentInfo">
|
||||||
<form>
|
<form>
|
||||||
<h5>{lang('PaymentCardTitle')}</h5>
|
<h5>{oldLang('PaymentCardTitle')}</h5>
|
||||||
<CardInput
|
<CardInput
|
||||||
onChange={handleCardNumberChange}
|
onChange={handleCardNumberChange}
|
||||||
value={state.cardNumber}
|
value={state.cardNumber}
|
||||||
error={formErrors.cardNumber}
|
error={formErrors.cardNumber && lang.withRegular(formErrors.cardNumber)}
|
||||||
/>
|
/>
|
||||||
{needCardholderName && (
|
{needCardholderName && (
|
||||||
<InputText
|
<InputText
|
||||||
label={lang('Checkout.NewCard.CardholderNamePlaceholder')}
|
label={oldLang('Checkout.NewCard.CardholderNamePlaceholder')}
|
||||||
onChange={handleCardholderChange}
|
onChange={handleCardholderChange}
|
||||||
value={state.cardholder}
|
value={state.cardholder}
|
||||||
inputMode="text"
|
inputMode="text"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
error={formErrors.cardholder}
|
error={formErrors.cardholder && lang.withRegular(formErrors.cardholder)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<section className="inline-inputs">
|
<section className="inline-inputs">
|
||||||
<ExpiryInput
|
<ExpiryInput
|
||||||
value={state.expiry}
|
value={state.expiry}
|
||||||
onChange={handleExpiryChange}
|
onChange={handleExpiryChange}
|
||||||
error={formErrors.expiry}
|
error={formErrors.expiry && lang.withRegular(formErrors.expiry)}
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
label={lang('lng_payments_card_cvc')}
|
label={oldLang('lng_payments_card_cvc')}
|
||||||
onChange={handleCvvChange}
|
onChange={handleCvvChange}
|
||||||
value={state.cvv}
|
value={state.cvv}
|
||||||
inputMode="numeric"
|
inputMode="numeric"
|
||||||
maxLength={3}
|
maxLength={3}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
error={formErrors.cvv}
|
error={formErrors.cvv && lang.withRegular(formErrors.cvv)}
|
||||||
teactExperimentControlled
|
teactExperimentControlled
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
{needCountry || needZip ? (
|
{needCountry || needZip ? (
|
||||||
<h5>{lang('PaymentBillingAddress')}</h5>
|
<h5>{oldLang('PaymentBillingAddress')}</h5>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
<section className="inline-inputs">
|
<section className="inline-inputs">
|
||||||
{needCountry && (
|
{needCountry && (
|
||||||
<Select
|
<Select
|
||||||
label={lang('PaymentShippingCountry')}
|
label={oldLang('PaymentShippingCountry')}
|
||||||
onChange={handleCountryChange}
|
onChange={handleCountryChange}
|
||||||
value={state.billingCountry}
|
value={state.billingCountry}
|
||||||
hasArrow={Boolean(true)}
|
hasArrow={Boolean(true)}
|
||||||
id="billing-country"
|
id="billing-country"
|
||||||
error={formErrors.billingCountry}
|
error={formErrors.billingCountry && lang.withRegular(formErrors.billingCountry)}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
ref={selectCountryRef}
|
ref={selectCountryRef}
|
||||||
>
|
>
|
||||||
@ -145,22 +147,22 @@ const PaymentInfo: FC<OwnProps> = ({
|
|||||||
)}
|
)}
|
||||||
{needZip && (
|
{needZip && (
|
||||||
<InputText
|
<InputText
|
||||||
label={lang('PaymentShippingZipPlaceholder')}
|
label={oldLang('PaymentShippingZipPlaceholder')}
|
||||||
onChange={handleBillingPostCodeChange}
|
onChange={handleBillingPostCodeChange}
|
||||||
value={state.billingZip}
|
value={state.billingZip}
|
||||||
inputMode="text"
|
inputMode="text"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
maxLength={12}
|
maxLength={12}
|
||||||
error={formErrors.billingZip}
|
error={formErrors.billingZip && lang.withRegular(formErrors.billingZip)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
<div className="checkbox">
|
<div className="checkbox">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={lang('PaymentCardSavePaymentInformation')}
|
label={oldLang('PaymentCardSavePaymentInformation')}
|
||||||
checked={canSaveCredentials ? state.saveCredentials : false}
|
checked={canSaveCredentials ? state.saveCredentials : false}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
subLabel={lang(canSaveCredentials ? 'Checkout.NewCard.SaveInfoHelp' : 'Checkout.2FA.Text')}
|
subLabel={oldLang(canSaveCredentials ? 'Checkout.NewCard.SaveInfoHelp' : 'Checkout.2FA.Text')}
|
||||||
onChange={handleChangeSaveCredentials}
|
onChange={handleChangeSaveCredentials}
|
||||||
disabled={!canSaveCredentials}
|
disabled={!canSaveCredentials}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -171,7 +171,7 @@ const PaymentModal: FC<OwnProps & StateProps> = ({
|
|||||||
paymentDispatch({
|
paymentDispatch({
|
||||||
type: 'setFormErrors',
|
type: 'setFormErrors',
|
||||||
payload: {
|
payload: {
|
||||||
[error.field]: error.message,
|
[error.field]: error.messageKey,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -250,8 +250,7 @@ const PaymentModal: FC<OwnProps & StateProps> = ({
|
|||||||
isOpen={Boolean(error)}
|
isOpen={Boolean(error)}
|
||||||
onClose={handleErrorModalClose}
|
onClose={handleErrorModalClose}
|
||||||
>
|
>
|
||||||
<h4>{error.description || 'Error'}</h4>
|
<h4>{error.descriptionKey ? lang.withRegular(error.descriptionKey) : lang('ErrorUnspecified')}</h4>
|
||||||
<p>{error.description || 'Error'}</p>
|
|
||||||
<div className="dialog-buttons mt-2">
|
<div className="dialog-buttons mt-2">
|
||||||
<Button
|
<Button
|
||||||
isText
|
isText
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import type { ApiCountry } from '../../api/types';
|
|||||||
import type { FormEditDispatch, FormState } from '../../hooks/reducers/usePaymentReducer';
|
import type { FormEditDispatch, FormState } from '../../hooks/reducers/usePaymentReducer';
|
||||||
|
|
||||||
import useFocusAfterAnimation from '../../hooks/useFocusAfterAnimation';
|
import useFocusAfterAnimation from '../../hooks/useFocusAfterAnimation';
|
||||||
|
import useLang from '../../hooks/useLang';
|
||||||
import useOldLang from '../../hooks/useOldLang';
|
import useOldLang from '../../hooks/useOldLang';
|
||||||
|
|
||||||
import Checkbox from '../ui/Checkbox';
|
import Checkbox from '../ui/Checkbox';
|
||||||
@ -49,7 +50,8 @@ const ShippingInfo: FC<OwnProps> = ({
|
|||||||
}
|
}
|
||||||
}, [state.countryIso2]);
|
}, [state.countryIso2]);
|
||||||
|
|
||||||
const lang = useOldLang();
|
const oldLang = useOldLang();
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
useFocusAfterAnimation(inputRef);
|
useFocusAfterAnimation(inputRef);
|
||||||
|
|
||||||
@ -104,46 +106,46 @@ const ShippingInfo: FC<OwnProps> = ({
|
|||||||
<form>
|
<form>
|
||||||
{needAddress ? (
|
{needAddress ? (
|
||||||
<div>
|
<div>
|
||||||
<h5>{lang('PaymentShippingAddress')}</h5>
|
<h5>{oldLang('PaymentShippingAddress')}</h5>
|
||||||
<InputText
|
<InputText
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
label={lang('PaymentShippingAddress1Placeholder')}
|
label={oldLang('PaymentShippingAddress1Placeholder')}
|
||||||
onChange={handleAddress1Change}
|
onChange={handleAddress1Change}
|
||||||
value={state.streetLine1}
|
value={state.streetLine1}
|
||||||
inputMode="text"
|
inputMode="text"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
error={formErrors.streetLine1}
|
error={formErrors.streetLine1 && lang.withRegular(formErrors.streetLine1)}
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
label={lang('PaymentShippingAddress2Placeholder')}
|
label={oldLang('PaymentShippingAddress2Placeholder')}
|
||||||
onChange={handleAddress2Change}
|
onChange={handleAddress2Change}
|
||||||
value={state.streetLine2}
|
value={state.streetLine2}
|
||||||
inputMode="text"
|
inputMode="text"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
error={formErrors.streetLine2}
|
error={formErrors.streetLine2 && lang.withRegular(formErrors.streetLine2)}
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
label={lang('PaymentShippingCityPlaceholder')}
|
label={oldLang('PaymentShippingCityPlaceholder')}
|
||||||
onChange={handleCityChange}
|
onChange={handleCityChange}
|
||||||
value={state.city}
|
value={state.city}
|
||||||
inputMode="text"
|
inputMode="text"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
error={formErrors.city}
|
error={formErrors.city && lang.withRegular(formErrors.city)}
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
label={lang('PaymentShippingStatePlaceholder')}
|
label={oldLang('PaymentShippingStatePlaceholder')}
|
||||||
onChange={handleStateChange}
|
onChange={handleStateChange}
|
||||||
value={state.state}
|
value={state.state}
|
||||||
inputMode="text"
|
inputMode="text"
|
||||||
error={formErrors.state}
|
error={formErrors.state && lang.withRegular(formErrors.state)}
|
||||||
/>
|
/>
|
||||||
<Select
|
<Select
|
||||||
label={lang('PaymentShippingCountry')}
|
label={oldLang('PaymentShippingCountry')}
|
||||||
onChange={handleCountryChange}
|
onChange={handleCountryChange}
|
||||||
value={state.countryIso2}
|
value={state.countryIso2}
|
||||||
hasArrow={Boolean(true)}
|
hasArrow={Boolean(true)}
|
||||||
id="shipping-country"
|
id="shipping-country"
|
||||||
error={formErrors.countryIso2}
|
error={formErrors.countryIso2 && lang.withRegular(formErrors.countryIso2)}
|
||||||
ref={selectCountryRef}
|
ref={selectCountryRef}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
@ -159,52 +161,52 @@ const ShippingInfo: FC<OwnProps> = ({
|
|||||||
</Select>
|
</Select>
|
||||||
|
|
||||||
<InputText
|
<InputText
|
||||||
label={lang('PaymentShippingZipPlaceholder')}
|
label={oldLang('PaymentShippingZipPlaceholder')}
|
||||||
onChange={handlePostCodeChange}
|
onChange={handlePostCodeChange}
|
||||||
value={state.postCode}
|
value={state.postCode}
|
||||||
inputMode="text"
|
inputMode="text"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
error={formErrors.postCode}
|
error={formErrors.postCode && lang.withRegular(formErrors.postCode)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
{ needName || needEmail || needPhone ? (
|
{ needName || needEmail || needPhone ? (
|
||||||
<h5>{lang('PaymentShippingReceiver')}</h5>
|
<h5>{oldLang('PaymentShippingReceiver')}</h5>
|
||||||
) : undefined }
|
) : undefined }
|
||||||
{ needName && (
|
{ needName && (
|
||||||
<InputText
|
<InputText
|
||||||
label={lang('PaymentShippingName')}
|
label={oldLang('PaymentShippingName')}
|
||||||
onChange={handleFullNameChange}
|
onChange={handleFullNameChange}
|
||||||
value={state.fullName}
|
value={state.fullName}
|
||||||
inputMode="text"
|
inputMode="text"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
error={formErrors.fullName}
|
error={formErrors.fullName && lang.withRegular(formErrors.fullName)}
|
||||||
/>
|
/>
|
||||||
) }
|
) }
|
||||||
{ needEmail && (
|
{ needEmail && (
|
||||||
<InputText
|
<InputText
|
||||||
label={lang('PaymentShippingEmailPlaceholder')}
|
label={oldLang('PaymentShippingEmailPlaceholder')}
|
||||||
onChange={handleEmailChange}
|
onChange={handleEmailChange}
|
||||||
value={state.email}
|
value={state.email}
|
||||||
inputMode="email"
|
inputMode="email"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
error={formErrors.email}
|
error={formErrors.email && lang.withRegular(formErrors.email)}
|
||||||
/>
|
/>
|
||||||
) }
|
) }
|
||||||
{ needPhone && (
|
{ needPhone && (
|
||||||
<InputText
|
<InputText
|
||||||
label={lang('PaymentShippingPhoneNumber')}
|
label={oldLang('PaymentShippingPhoneNumber')}
|
||||||
onChange={handlePhoneChange}
|
onChange={handlePhoneChange}
|
||||||
value={state.phone}
|
value={state.phone}
|
||||||
inputMode="tel"
|
inputMode="tel"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
error={formErrors.phone}
|
error={formErrors.phone && lang.withRegular(formErrors.phone)}
|
||||||
ref={phoneRef}
|
ref={phoneRef}
|
||||||
/>
|
/>
|
||||||
) }
|
) }
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={lang('PaymentShippingSave')}
|
label={oldLang('PaymentShippingSave')}
|
||||||
subLabel={lang('PaymentShippingSaveInfo')}
|
subLabel={oldLang('PaymentShippingSaveInfo')}
|
||||||
checked={Boolean(state.saveInfo)}
|
checked={Boolean(state.saveInfo)}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onChange={handleSaveInfoChange}
|
onChange={handleSaveInfoChange}
|
||||||
|
|||||||
@ -18,7 +18,6 @@ import useOldLang from '../../../hooks/useOldLang';
|
|||||||
import AboutMonetizationModal from '../../common/AboutMonetizationModal.async';
|
import AboutMonetizationModal from '../../common/AboutMonetizationModal.async';
|
||||||
import Icon from '../../common/icons/Icon';
|
import Icon from '../../common/icons/Icon';
|
||||||
import SafeLink from '../../common/SafeLink';
|
import SafeLink from '../../common/SafeLink';
|
||||||
import VerificationMonetizationModal from '../../common/VerificationMonetizationModal.async';
|
|
||||||
import Button from '../../ui/Button';
|
import Button from '../../ui/Button';
|
||||||
import ConfirmDialog from '../../ui/ConfirmDialog';
|
import ConfirmDialog from '../../ui/ConfirmDialog';
|
||||||
import Link from '../../ui/Link';
|
import Link from '../../ui/Link';
|
||||||
@ -53,9 +52,6 @@ type StateProps = {
|
|||||||
isCreator?: boolean;
|
isCreator?: boolean;
|
||||||
isChannelRevenueWithdrawalEnabled?: boolean;
|
isChannelRevenueWithdrawalEnabled?: boolean;
|
||||||
hasPassword?: boolean;
|
hasPassword?: boolean;
|
||||||
passwordHint?: string;
|
|
||||||
error?: string;
|
|
||||||
isLoading?: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const MonetizationStatistics = ({
|
const MonetizationStatistics = ({
|
||||||
@ -65,11 +61,8 @@ const MonetizationStatistics = ({
|
|||||||
isCreator,
|
isCreator,
|
||||||
isChannelRevenueWithdrawalEnabled,
|
isChannelRevenueWithdrawalEnabled,
|
||||||
hasPassword,
|
hasPassword,
|
||||||
passwordHint,
|
|
||||||
error,
|
|
||||||
isLoading,
|
|
||||||
}: StateProps) => {
|
}: StateProps) => {
|
||||||
const { loadChannelMonetizationStatistics, loadPasswordInfo } = getActions();
|
const { loadChannelMonetizationStatistics, openMonetizationVerificationModal, loadPasswordInfo } = getActions();
|
||||||
const oldLang = useOldLang();
|
const oldLang = useOldLang();
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
|
|
||||||
@ -79,9 +72,6 @@ const MonetizationStatistics = ({
|
|||||||
const loadedCharts = useRef<string[]>([]);
|
const loadedCharts = useRef<string[]>([]);
|
||||||
const forceUpdate = useForceUpdate();
|
const forceUpdate = useForceUpdate();
|
||||||
const [isAboutMonetizationModalOpen, openAboutMonetizationModal, closeAboutMonetizationModal] = useFlag(false);
|
const [isAboutMonetizationModalOpen, openAboutMonetizationModal, closeAboutMonetizationModal] = useFlag(false);
|
||||||
const [
|
|
||||||
isVerificationMonetizationModalOpen, openVerificationMonetizationModal, closeVerificationMonetizationModal,
|
|
||||||
] = useFlag(false);
|
|
||||||
const [isConfirmPasswordDialogOpen, openConfirmPasswordDialogOpen, closeConfirmPasswordDialogOpen] = useFlag();
|
const [isConfirmPasswordDialogOpen, openConfirmPasswordDialogOpen, closeConfirmPasswordDialogOpen] = useFlag();
|
||||||
const availableBalance = statistics?.balances?.availableBalance;
|
const availableBalance = statistics?.balances?.availableBalance;
|
||||||
const isWithdrawalEnabled = statistics?.balances?.isWithdrawalEnabled;
|
const isWithdrawalEnabled = statistics?.balances?.isWithdrawalEnabled;
|
||||||
@ -206,7 +196,9 @@ const MonetizationStatistics = ({
|
|||||||
|
|
||||||
const verificationMonetizationHandler = useLastCallback(() => {
|
const verificationMonetizationHandler = useLastCallback(() => {
|
||||||
if (hasPassword) {
|
if (hasPassword) {
|
||||||
openVerificationMonetizationModal();
|
openMonetizationVerificationModal({
|
||||||
|
chatId,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
openConfirmPasswordDialogOpen();
|
openConfirmPasswordDialogOpen();
|
||||||
}
|
}
|
||||||
@ -259,14 +251,6 @@ const MonetizationStatistics = ({
|
|||||||
isOpen={isAboutMonetizationModalOpen}
|
isOpen={isAboutMonetizationModalOpen}
|
||||||
onClose={closeAboutMonetizationModal}
|
onClose={closeAboutMonetizationModal}
|
||||||
/>
|
/>
|
||||||
<VerificationMonetizationModal
|
|
||||||
chatId={chatId}
|
|
||||||
isOpen={isVerificationMonetizationModalOpen}
|
|
||||||
onClose={closeVerificationMonetizationModal}
|
|
||||||
passwordHint={passwordHint}
|
|
||||||
error={error}
|
|
||||||
isLoading={isLoading}
|
|
||||||
/>
|
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
isOnlyConfirm
|
isOnlyConfirm
|
||||||
isOpen={isConfirmPasswordDialogOpen}
|
isOpen={isConfirmPasswordDialogOpen}
|
||||||
@ -289,12 +273,7 @@ export default memo(withGlobal(
|
|||||||
hasPassword,
|
hasPassword,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
twoFaSettings: {
|
|
||||||
hint: passwordHint,
|
|
||||||
},
|
|
||||||
} = global;
|
} = global;
|
||||||
const isLoading = global.monetizationInfo?.isLoading;
|
|
||||||
const error = global.monetizationInfo?.error;
|
|
||||||
const monetizationStatistics = tabState.monetizationStatistics;
|
const monetizationStatistics = tabState.monetizationStatistics;
|
||||||
const chatId = monetizationStatistics && monetizationStatistics.chatId;
|
const chatId = monetizationStatistics && monetizationStatistics.chatId;
|
||||||
const chat = chatId ? selectChat(global, chatId) : undefined;
|
const chat = chatId ? selectChat(global, chatId) : undefined;
|
||||||
@ -312,9 +291,6 @@ export default memo(withGlobal(
|
|||||||
isCreator,
|
isCreator,
|
||||||
isChannelRevenueWithdrawalEnabled,
|
isChannelRevenueWithdrawalEnabled,
|
||||||
hasPassword,
|
hasPassword,
|
||||||
passwordHint,
|
|
||||||
error,
|
|
||||||
isLoading,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(MonetizationStatistics));
|
)(MonetizationStatistics));
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import type { IconName } from '../../types/icons';
|
|||||||
import { getPeerTitle, getUserFullName } from '../../global/helpers';
|
import { getPeerTitle, getUserFullName } from '../../global/helpers';
|
||||||
import { selectPeerStory, selectTabState } from '../../global/selectors';
|
import { selectPeerStory, selectTabState } from '../../global/selectors';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
|
import { getHours } from '../../util/dates/units';
|
||||||
import stopEvent from '../../util/stopEvent';
|
import stopEvent from '../../util/stopEvent';
|
||||||
|
|
||||||
import useFlag from '../../hooks/useFlag';
|
import useFlag from '../../hooks/useFlag';
|
||||||
@ -299,7 +300,7 @@ function StorySettings({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderPrivacyList() {
|
function renderPrivacyList() {
|
||||||
const storyLifeTime = story ? convertSecondsToHours(story.expireDate - story.date) : 0;
|
const storyLifeTime = story ? getHours(story.expireDate - story.date) : 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -419,15 +420,3 @@ export default memo(withGlobal<OwnProps>((global): StateProps => {
|
|||||||
currentUserId: global.currentUserId!,
|
currentUserId: global.currentUserId!,
|
||||||
};
|
};
|
||||||
})(StorySettings));
|
})(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/stars';
|
||||||
import './ui/reactions';
|
import './ui/reactions';
|
||||||
import './ui/stories';
|
import './ui/stories';
|
||||||
|
import './ui/statistics';
|
||||||
import './apiUpdaters/initial';
|
import './apiUpdaters/initial';
|
||||||
import './apiUpdaters/chats';
|
import './apiUpdaters/chats';
|
||||||
import './apiUpdaters/messages';
|
import './apiUpdaters/messages';
|
||||||
@ -41,6 +42,5 @@ import './apiUpdaters/symbols';
|
|||||||
import './apiUpdaters/misc';
|
import './apiUpdaters/misc';
|
||||||
import './apiUpdaters/settings';
|
import './apiUpdaters/settings';
|
||||||
import './apiUpdaters/twoFaSettings';
|
import './apiUpdaters/twoFaSettings';
|
||||||
import './apiUpdaters/password';
|
|
||||||
import './apiUpdaters/calls';
|
import './apiUpdaters/calls';
|
||||||
import './apiUpdaters/payments';
|
import './apiUpdaters/payments';
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import type {
|
|||||||
ApiInputInvoice, ApiInputInvoiceStarGift, ApiInputInvoiceStarGiftUpgrade, ApiRequestInputInvoice,
|
ApiInputInvoice, ApiInputInvoiceStarGift, ApiInputInvoiceStarGiftUpgrade, ApiRequestInputInvoice,
|
||||||
} from '../../../api/types';
|
} from '../../../api/types';
|
||||||
import type { ApiCredentials } from '../../../components/payment/PaymentModal';
|
import type { ApiCredentials } from '../../../components/payment/PaymentModal';
|
||||||
|
import type { RegularLangFnParameters } from '../../../util/localization';
|
||||||
import type {
|
import type {
|
||||||
ActionReturnType, GlobalState, TabArgs,
|
ActionReturnType, GlobalState, TabArgs,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
@ -397,7 +398,7 @@ async function sendSmartGlocalCredentials<T extends GlobalState>(
|
|||||||
|
|
||||||
if (result.status !== 'ok') {
|
if (result.status !== 'ok') {
|
||||||
// TODO после получения документации сделать аналог getStripeError(result.error);
|
// TODO после получения документации сделать аналог getStripeError(result.error);
|
||||||
const error = { description: 'payment error' };
|
const error = { descriptionKey: { key: 'ErrorUnexpected' } satisfies RegularLangFnParameters };
|
||||||
global = getGlobal();
|
global = getGlobal();
|
||||||
global = updateTabState(global, {
|
global = updateTabState(global, {
|
||||||
payment: {
|
payment: {
|
||||||
@ -554,9 +555,9 @@ addActionHandler('validatePaymentPassword', async (global, actions, payload): Pr
|
|||||||
global = getGlobal();
|
global = getGlobal();
|
||||||
|
|
||||||
if (!result) {
|
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) {
|
} 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 {
|
} else {
|
||||||
global = updatePayment(global, { temporaryPassword: result, step: PaymentStep.Checkout }, tabId);
|
global = updatePayment(global, { temporaryPassword: result, step: PaymentStep.Checkout }, tabId);
|
||||||
}
|
}
|
||||||
@ -1063,3 +1064,51 @@ addActionHandler('openUniqueGiftBySlug', async (global, actions, payload): Promi
|
|||||||
|
|
||||||
actions.openGiftInfoModal({ gift, tabId });
|
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 { areDeepEqual } from '../../../util/areDeepEqual';
|
||||||
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
||||||
import { callApi } from '../../../api/gramjs';
|
import { callApi } from '../../../api/gramjs';
|
||||||
@ -7,10 +5,10 @@ import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
|||||||
import {
|
import {
|
||||||
updateChannelMonetizationStatistics,
|
updateChannelMonetizationStatistics,
|
||||||
updateMessageStatistics,
|
updateMessageStatistics,
|
||||||
updateMonetizationInfo,
|
|
||||||
updateStatistics,
|
updateStatistics,
|
||||||
updateStatisticsGraph,
|
updateStatisticsGraph,
|
||||||
updateStoryStatistics,
|
updateStoryStatistics,
|
||||||
|
updateVerifyMonetizationModal,
|
||||||
} from '../../reducers';
|
} from '../../reducers';
|
||||||
import {
|
import {
|
||||||
selectChat,
|
selectChat,
|
||||||
@ -229,12 +227,14 @@ addActionHandler('loadStoryPublicForwards', async (global, actions, payload): Pr
|
|||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('loadMonetizationRevenueWithdrawalUrl', async (global, actions, payload): Promise<void> => {
|
addActionHandler('processMonetizationRevenueWithdrawalUrl', async (global, actions, payload): Promise<void> => {
|
||||||
const {
|
const {
|
||||||
peerId, currentPassword, onSuccess, tabId = getCurrentTabId(),
|
peerId, currentPassword, tabId = getCurrentTabId(),
|
||||||
} = payload;
|
} = payload;
|
||||||
|
|
||||||
global = updateMonetizationInfo(global, { isLoading: true, error: undefined });
|
global = updateVerifyMonetizationModal(global, {
|
||||||
|
isLoading: true,
|
||||||
|
}, tabId);
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
|
|
||||||
const peer = selectPeer(global, peerId);
|
const peer = selectPeer(global, peerId);
|
||||||
@ -242,27 +242,26 @@ addActionHandler('loadMonetizationRevenueWithdrawalUrl', async (global, actions,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await callApi('loadMonetizationRevenueWithdrawalUrl', { peer, currentPassword });
|
const result = await callApi('fetchMonetizationRevenueWithdrawalUrl', { peer, currentPassword });
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
global = getGlobal();
|
global = getGlobal();
|
||||||
global = updateMonetizationInfo(global, { isLoading: false });
|
global = updateVerifyMonetizationModal(global, {
|
||||||
|
isLoading: false,
|
||||||
|
errorKey: 'error' in result ? result.messageKey : undefined,
|
||||||
|
}, tabId);
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
|
|
||||||
if (result) {
|
if ('url' in result) {
|
||||||
onSuccess();
|
|
||||||
actions.openUrl({
|
actions.openUrl({
|
||||||
url: result.url,
|
url: result.url,
|
||||||
shouldSkipModal: true,
|
shouldSkipModal: true,
|
||||||
tabId,
|
tabId,
|
||||||
ignoreDeepLinks: true,
|
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> => {
|
addActionHandler('checkPassword', async (global, actions, payload): Promise<void> => {
|
||||||
const { currentPassword, onSuccess } = payload;
|
const { currentPassword, onSuccess } = payload;
|
||||||
|
|
||||||
global = updateTwoFaSettings(global, { isLoading: true, error: undefined });
|
global = updateTwoFaSettings(global, { isLoading: true, errorKey: undefined });
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
|
|
||||||
const isSuccess = await callApi('checkPassword', currentPassword);
|
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> => {
|
addActionHandler('clearPassword', async (global, actions, payload): Promise<void> => {
|
||||||
const { currentPassword, onSuccess } = payload;
|
const { currentPassword, onSuccess } = payload;
|
||||||
|
|
||||||
global = updateTwoFaSettings(global, { isLoading: true, error: undefined });
|
global = updateTwoFaSettings(global, { isLoading: true, errorKey: undefined });
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
|
|
||||||
const isSuccess = await callApi('clearPassword', currentPassword);
|
const isSuccess = await callApi('clearPassword', currentPassword);
|
||||||
@ -55,7 +55,7 @@ addActionHandler('updatePassword', async (global, actions, payload): Promise<voi
|
|||||||
currentPassword, password, hint, email, onSuccess,
|
currentPassword, password, hint, email, onSuccess,
|
||||||
} = payload;
|
} = payload;
|
||||||
|
|
||||||
global = updateTwoFaSettings(global, { isLoading: true, error: undefined });
|
global = updateTwoFaSettings(global, { isLoading: true, errorKey: undefined });
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
|
|
||||||
const isSuccess = await callApi('updatePassword', currentPassword, password, hint, email);
|
const isSuccess = await callApi('updatePassword', currentPassword, password, hint, email);
|
||||||
@ -74,7 +74,7 @@ addActionHandler('updateRecoveryEmail', async (global, actions, payload): Promis
|
|||||||
currentPassword, email, onSuccess,
|
currentPassword, email, onSuccess,
|
||||||
} = payload;
|
} = payload;
|
||||||
|
|
||||||
global = updateTwoFaSettings(global, { isLoading: true, error: undefined });
|
global = updateTwoFaSettings(global, { isLoading: true, errorKey: undefined });
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
|
|
||||||
const isSuccess = await callApi('updateRecoveryEmail', currentPassword, email);
|
const isSuccess = await callApi('updateRecoveryEmail', currentPassword, email);
|
||||||
@ -95,5 +95,5 @@ addActionHandler('provideTwoFaEmailCode', (global, actions, payload): ActionRetu
|
|||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('clearTwoFaError', (global): ActionReturnType => {
|
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,
|
...global,
|
||||||
twoFaSettings: {
|
twoFaSettings: {
|
||||||
...global.twoFaSettings,
|
...global.twoFaSettings,
|
||||||
error: update.message,
|
errorKey: update.messageKey,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import {
|
|||||||
clearStarPayment, openStarsTransactionModal,
|
clearStarPayment, openStarsTransactionModal,
|
||||||
} from '../../reducers';
|
} from '../../reducers';
|
||||||
import { updateTabState } from '../../reducers/tabs';
|
import { updateTabState } from '../../reducers/tabs';
|
||||||
import { selectChatMessage, selectStarsPayment } from '../../selectors';
|
import { selectChatMessage, selectStarsPayment, selectTabState } from '../../selectors';
|
||||||
|
|
||||||
addActionHandler('processOriginStarsPayment', (global, actions, payload): ActionReturnType => {
|
addActionHandler('processOriginStarsPayment', (global, actions, payload): ActionReturnType => {
|
||||||
const { originData, status, tabId = getCurrentTabId() } = payload;
|
const { originData, status, tabId = getCurrentTabId() } = payload;
|
||||||
@ -302,3 +302,35 @@ addActionHandler('closeGiftUpgradeModal', (global, actions, payload): ActionRetu
|
|||||||
giftUpgradeModal: undefined,
|
giftUpgradeModal: undefined,
|
||||||
}, tabId);
|
}, 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,
|
boostStatistics: undefined,
|
||||||
}, tabId);
|
}, 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 { ANONYMOUS_USER_ID, SERVICE_NOTIFICATIONS_USER_ID } from '../../config';
|
||||||
import { formatFullDate, formatTime } from '../../util/dates/dateFormat';
|
import { formatFullDate, formatTime } from '../../util/dates/dateFormat';
|
||||||
|
import { DAY } from '../../util/dates/units';
|
||||||
import { orderBy } from '../../util/iteratees';
|
import { orderBy } from '../../util/iteratees';
|
||||||
import { formatPhoneNumber } from '../../util/phoneNumber';
|
import { formatPhoneNumber } from '../../util/phoneNumber';
|
||||||
import { prepareSearchWordsForNeedle } from '../../util/searchWords';
|
import { prepareSearchWordsForNeedle } from '../../util/searchWords';
|
||||||
@ -227,11 +228,11 @@ export function sortUserIds(
|
|||||||
|
|
||||||
switch (userStatus.type) {
|
switch (userStatus.type) {
|
||||||
case 'userStatusRecently':
|
case 'userStatusRecently':
|
||||||
return now - 60 * 60 * 24;
|
return now - DAY;
|
||||||
case 'userStatusLastWeek':
|
case 'userStatusLastWeek':
|
||||||
return now - 60 * 60 * 24 * 7;
|
return now - DAY * 7;
|
||||||
case 'userStatusLastMonth':
|
case 'userStatusLastMonth':
|
||||||
return now - 60 * 60 * 24 * 7 * 30;
|
return now - DAY * 7 * 30;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -313,8 +313,6 @@ export const INITIAL_GLOBAL_STATE: GlobalState = {
|
|||||||
isMinimized: false,
|
isMinimized: false,
|
||||||
isHidden: false,
|
isHidden: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
monetizationInfo: {},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const INITIAL_TAB_STATE: TabState = {
|
export const INITIAL_TAB_STATE: TabState = {
|
||||||
|
|||||||
@ -13,5 +13,4 @@ export * from './statistics';
|
|||||||
export * from './stories';
|
export * from './stories';
|
||||||
export * from './translations';
|
export * from './translations';
|
||||||
export * from './peers';
|
export * from './peers';
|
||||||
export * from './password';
|
|
||||||
export * from './topics';
|
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,
|
ApiChannelMonetizationStatistics,
|
||||||
ApiChannelStatistics, ApiGroupStatistics, ApiPostStatistics, StatisticsGraph,
|
ApiChannelStatistics, ApiGroupStatistics, ApiPostStatistics, StatisticsGraph,
|
||||||
} from '../../api/types';
|
} from '../../api/types';
|
||||||
import type { GlobalState, TabArgs } from '../types';
|
import type { GlobalState, TabArgs, TabState } from '../types';
|
||||||
|
|
||||||
import { getCurrentTabId } from '../../util/establishMultitabRole';
|
import { getCurrentTabId } from '../../util/establishMultitabRole';
|
||||||
import { selectTabState } from '../selectors';
|
import { selectTabState } from '../selectors';
|
||||||
@ -78,3 +78,20 @@ export function updateChannelMonetizationStatistics<T extends GlobalState>(
|
|||||||
},
|
},
|
||||||
}, tabId);
|
}, 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>;
|
updatePerformanceSettings: Partial<PerformanceType>;
|
||||||
loadPasswordInfo: undefined;
|
loadPasswordInfo: undefined;
|
||||||
clearTwoFaError: undefined;
|
clearTwoFaError: undefined;
|
||||||
clearMonetizationInfo: undefined;
|
openMonetizationVerificationModal: {
|
||||||
|
chatId: string;
|
||||||
|
} & WithTabId;
|
||||||
|
clearMonetizationVerificationError: WithTabId | undefined;
|
||||||
|
closeMonetizationVerificationModal: WithTabId | undefined;
|
||||||
updatePassword: {
|
updatePassword: {
|
||||||
currentPassword: string;
|
currentPassword: string;
|
||||||
password: string;
|
password: string;
|
||||||
@ -756,10 +760,9 @@ export interface ActionPayloads {
|
|||||||
peerId: string;
|
peerId: string;
|
||||||
} & WithTabId;
|
} & WithTabId;
|
||||||
|
|
||||||
loadMonetizationRevenueWithdrawalUrl: {
|
processMonetizationRevenueWithdrawalUrl: {
|
||||||
peerId: string;
|
peerId: string;
|
||||||
currentPassword: string;
|
currentPassword: string;
|
||||||
onSuccess: VoidFunction;
|
|
||||||
} & WithTabId;
|
} & WithTabId;
|
||||||
|
|
||||||
// ui
|
// ui
|
||||||
@ -2323,6 +2326,15 @@ export interface ActionPayloads {
|
|||||||
shouldKeepOriginalDetails?: boolean;
|
shouldKeepOriginalDetails?: boolean;
|
||||||
upgradeStars?: number;
|
upgradeStars?: number;
|
||||||
} & WithTabId;
|
} & WithTabId;
|
||||||
|
openGiftWithdrawModal: {
|
||||||
|
gift: ApiSavedStarGift;
|
||||||
|
} & WithTabId;
|
||||||
|
clearGiftWithdrawError: WithTabId | undefined;
|
||||||
|
closeGiftWithdrawModal: WithTabId | undefined;
|
||||||
|
processStarGiftWithdrawal: {
|
||||||
|
gift: ApiInputSavedStarGift;
|
||||||
|
password: string;
|
||||||
|
} & WithTabId;
|
||||||
loadPeerSavedGifts: {
|
loadPeerSavedGifts: {
|
||||||
peerId: string;
|
peerId: string;
|
||||||
shouldRefresh?: boolean;
|
shouldRefresh?: boolean;
|
||||||
|
|||||||
@ -109,15 +109,10 @@ export type GlobalState = {
|
|||||||
twoFaSettings: {
|
twoFaSettings: {
|
||||||
hint?: string;
|
hint?: string;
|
||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
error?: string;
|
errorKey?: RegularLangFnParameters;
|
||||||
waitingEmailCodeLength?: number;
|
waitingEmailCodeLength?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
monetizationInfo: {
|
|
||||||
isLoading?: boolean;
|
|
||||||
error?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
attachmentSettings: {
|
attachmentSettings: {
|
||||||
shouldCompress: boolean;
|
shouldCompress: boolean;
|
||||||
shouldSendGrouped: boolean;
|
shouldSendGrouped: boolean;
|
||||||
|
|||||||
@ -82,6 +82,7 @@ import type {
|
|||||||
} from '../../types';
|
} from '../../types';
|
||||||
import type { WebApp, WebAppModalStateType } from '../../types/webapp';
|
import type { WebApp, WebAppModalStateType } from '../../types/webapp';
|
||||||
import type { SearchResultKey } from '../../util/keys/searchResultKey';
|
import type { SearchResultKey } from '../../util/keys/searchResultKey';
|
||||||
|
import type { RegularLangFnParameters } from '../../util/localization';
|
||||||
import type { CallbackAction } from './actions';
|
import type { CallbackAction } from './actions';
|
||||||
|
|
||||||
export type TabState = {
|
export type TabState = {
|
||||||
@ -377,8 +378,8 @@ export type TabState = {
|
|||||||
receipt?: ApiReceiptRegular;
|
receipt?: ApiReceiptRegular;
|
||||||
error?: {
|
error?: {
|
||||||
field?: string;
|
field?: string;
|
||||||
message?: string;
|
messageKey?: RegularLangFnParameters;
|
||||||
description?: string;
|
descriptionKey?: RegularLangFnParameters;
|
||||||
};
|
};
|
||||||
isPaymentModalOpen?: boolean;
|
isPaymentModalOpen?: boolean;
|
||||||
isExtendedMedia?: boolean;
|
isExtendedMedia?: boolean;
|
||||||
@ -720,6 +721,12 @@ export type TabState = {
|
|||||||
gift?: ApiSavedStarGift;
|
gift?: ApiSavedStarGift;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
giftWithdrawModal?: {
|
||||||
|
gift: ApiSavedStarGift;
|
||||||
|
isLoading?: boolean;
|
||||||
|
errorKey?: RegularLangFnParameters;
|
||||||
|
};
|
||||||
|
|
||||||
suggestedStatusModal?: {
|
suggestedStatusModal?: {
|
||||||
botId: string;
|
botId: string;
|
||||||
webAppKey?: string;
|
webAppKey?: string;
|
||||||
@ -727,5 +734,11 @@ export type TabState = {
|
|||||||
duration?: number;
|
duration?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
monetizationVerificationModal?: {
|
||||||
|
chatId: string;
|
||||||
|
isLoading?: boolean;
|
||||||
|
errorKey?: RegularLangFnParameters;
|
||||||
|
};
|
||||||
|
|
||||||
isWaitingForStarGiftUpgrade?: true;
|
isWaitingForStarGiftUpgrade?: true;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import type { RegularLangFnParameters } from '../../util/localization';
|
||||||
import type { Dispatch, StateReducer } from '../useReducer';
|
import type { Dispatch, StateReducer } from '../useReducer';
|
||||||
|
|
||||||
import useReducer from '../useReducer';
|
import useReducer from '../useReducer';
|
||||||
@ -21,7 +22,7 @@ export type FormState = {
|
|||||||
billingZip: string;
|
billingZip: string;
|
||||||
saveInfo: boolean;
|
saveInfo: boolean;
|
||||||
saveCredentials: boolean;
|
saveCredentials: boolean;
|
||||||
formErrors: Record<string, string>;
|
formErrors: Partial<Record<string, RegularLangFnParameters>>;
|
||||||
tipAmount: number;
|
tipAmount: number;
|
||||||
savedCredentialId: string;
|
savedCredentialId: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import type TelegramClient from './TelegramClient';
|
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 Api from '../tl/api';
|
||||||
|
|
||||||
import { generateRandomBytes } from '../Helpers';
|
import { generateRandomBytes } from '../Helpers';
|
||||||
@ -16,13 +17,8 @@ export interface TwoFaParams {
|
|||||||
onEmailCodeError?: (err: Error) => void;
|
onEmailCodeError?: (err: Error) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TwoFaPasswordParams {
|
export type TmpPasswordResult = Api.account.TmpPassword | WrappedError | undefined;
|
||||||
currentPassword?: string;
|
export type PasswordResult = Api.TypeInputCheckPasswordSRP | WrappedError | undefined;
|
||||||
onPasswordCodeError?: (err: Error) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type TmpPasswordResult = Api.account.TmpPassword | { error: string } | undefined;
|
|
||||||
export type PasswordResult = Api.TypeInputCheckPasswordSRP | { error: string } | undefined;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the 2FA settings of the logged in user.
|
* 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);
|
const inputPassword = await computeCheck(pwd, currentPassword);
|
||||||
try {
|
const result = await client.invoke(new Api.account.GetTmpPassword({
|
||||||
const result = await client.invoke(new Api.account.GetTmpPassword({
|
password: inputPassword,
|
||||||
password: inputPassword,
|
period: ttl,
|
||||||
period: ttl,
|
}));
|
||||||
}));
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (err: unknown) {
|
|
||||||
if (err instanceof RPCError && err.errorMessage === 'PASSWORD_HASH_INVALID') {
|
|
||||||
return { error: err.errorMessage };
|
|
||||||
}
|
|
||||||
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getCurrentPassword(
|
export async function getCurrentPassword(
|
||||||
client: TelegramClient,
|
client: TelegramClient,
|
||||||
{
|
currentPassword?: string,
|
||||||
currentPassword,
|
|
||||||
onPasswordCodeError,
|
|
||||||
}: TwoFaPasswordParams,
|
|
||||||
): Promise<PasswordResult> {
|
): Promise<PasswordResult> {
|
||||||
const pwd = await client.invoke(new Api.account.GetPassword());
|
const pwd = await client.invoke(new Api.account.GetPassword());
|
||||||
|
|
||||||
@ -172,16 +157,5 @@ export async function getCurrentPassword(
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
return currentPassword ? await computeCheck(pwd, currentPassword!) : new Api.InputCheckPasswordEmpty();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,6 @@ import {
|
|||||||
TwoFaParams,
|
TwoFaParams,
|
||||||
TmpPasswordResult,
|
TmpPasswordResult,
|
||||||
PasswordResult,
|
PasswordResult,
|
||||||
TwoFaPasswordParams,
|
|
||||||
} from './2fa';
|
} from './2fa';
|
||||||
import RequestState from '../network/RequestState';
|
import RequestState from '../network/RequestState';
|
||||||
import Deferred from '../../../util/Deferred';
|
import Deferred from '../../../util/Deferred';
|
||||||
@ -1264,8 +1263,8 @@ class TelegramClient {
|
|||||||
return getTmpPassword(this, currentPassword, ttl);
|
return getTmpPassword(this, currentPassword, ttl);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentPassword(params: TwoFaPasswordParams): Promise<PasswordResult | undefined> {
|
getCurrentPassword(currentPassword?: string): Promise<PasswordResult | undefined> {
|
||||||
return getCurrentPassword(this, params);
|
return getCurrentPassword(this, currentPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
// event region
|
// event region
|
||||||
|
|||||||
@ -136,7 +136,7 @@ export class EmailUnconfirmedError extends BadRequestError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PasswordModifiedError extends BadRequestError {
|
export class PasswordFreshError extends BadRequestError {
|
||||||
public seconds: number;
|
public seconds: number;
|
||||||
|
|
||||||
constructor(args: any) {
|
constructor(args: any) {
|
||||||
@ -159,6 +159,6 @@ export const rpcErrorRe = new Map<RegExp, any>([
|
|||||||
[/USER_MIGRATE_(\d+)/, UserMigrateError],
|
[/USER_MIGRATE_(\d+)/, UserMigrateError],
|
||||||
[/NETWORK_MIGRATE_(\d+)/, NetworkMigrateError],
|
[/NETWORK_MIGRATE_(\d+)/, NetworkMigrateError],
|
||||||
[/EMAIL_UNCONFIRMED_(\d+)/, EmailUnconfirmedError],
|
[/EMAIL_UNCONFIRMED_(\d+)/, EmailUnconfirmedError],
|
||||||
[/PASSWORD_TOO_FRESH_(\d+)/, PasswordModifiedError],
|
[/PASSWORD_TOO_FRESH_(\d+)/, PasswordFreshError],
|
||||||
[/^Timeout$/, TimedOutError],
|
[/^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.transferStarGift#7f18176a stargift:InputSavedStarGift to_id:InputPeer = Updates;
|
||||||
payments.getUniqueStarGift#a1974d72 slug:string = payments.UniqueStarGift;
|
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.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.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.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;
|
phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall;
|
||||||
|
|||||||
@ -310,6 +310,7 @@
|
|||||||
"payments.upgradeStarGift",
|
"payments.upgradeStarGift",
|
||||||
"payments.transferStarGift",
|
"payments.transferStarGift",
|
||||||
"payments.getUniqueStarGift",
|
"payments.getUniqueStarGift",
|
||||||
|
"payments.getStarGiftWithdrawalUrl",
|
||||||
"langpack.getLangPack",
|
"langpack.getLangPack",
|
||||||
"langpack.getStrings",
|
"langpack.getStrings",
|
||||||
"langpack.getLanguages",
|
"langpack.getLanguages",
|
||||||
|
|||||||
@ -124,165 +124,166 @@ $icons-map: (
|
|||||||
"fontsize": "\f157",
|
"fontsize": "\f157",
|
||||||
"forums": "\f158",
|
"forums": "\f158",
|
||||||
"forward": "\f159",
|
"forward": "\f159",
|
||||||
"fullscreen": "\f15a",
|
"fragment": "\f15a",
|
||||||
"gifs": "\f15b",
|
"fullscreen": "\f15b",
|
||||||
"gift": "\f15c",
|
"gifs": "\f15c",
|
||||||
"group-filled": "\f15d",
|
"gift": "\f15d",
|
||||||
"group": "\f15e",
|
"group-filled": "\f15e",
|
||||||
"grouped-disable": "\f15f",
|
"group": "\f15f",
|
||||||
"grouped": "\f160",
|
"grouped-disable": "\f160",
|
||||||
"hand-stop": "\f161",
|
"grouped": "\f161",
|
||||||
"hashtag": "\f162",
|
"hand-stop": "\f162",
|
||||||
"heart-outline": "\f163",
|
"hashtag": "\f163",
|
||||||
"heart": "\f164",
|
"heart-outline": "\f164",
|
||||||
"help": "\f165",
|
"heart": "\f165",
|
||||||
"info-filled": "\f166",
|
"help": "\f166",
|
||||||
"info": "\f167",
|
"info-filled": "\f167",
|
||||||
"install": "\f168",
|
"info": "\f168",
|
||||||
"italic": "\f169",
|
"install": "\f169",
|
||||||
"key": "\f16a",
|
"italic": "\f16a",
|
||||||
"keyboard": "\f16b",
|
"key": "\f16b",
|
||||||
"lamp": "\f16c",
|
"keyboard": "\f16c",
|
||||||
"language": "\f16d",
|
"lamp": "\f16d",
|
||||||
"large-pause": "\f16e",
|
"language": "\f16e",
|
||||||
"large-play": "\f16f",
|
"large-pause": "\f16f",
|
||||||
"link-badge": "\f170",
|
"large-play": "\f170",
|
||||||
"link-broken": "\f171",
|
"link-badge": "\f171",
|
||||||
"link": "\f172",
|
"link-broken": "\f172",
|
||||||
"location": "\f173",
|
"link": "\f173",
|
||||||
"lock-badge": "\f174",
|
"location": "\f174",
|
||||||
"lock": "\f175",
|
"lock-badge": "\f175",
|
||||||
"logout": "\f176",
|
"lock": "\f176",
|
||||||
"loop": "\f177",
|
"logout": "\f177",
|
||||||
"mention": "\f178",
|
"loop": "\f178",
|
||||||
"message-failed": "\f179",
|
"mention": "\f179",
|
||||||
"message-pending": "\f17a",
|
"message-failed": "\f17a",
|
||||||
"message-read": "\f17b",
|
"message-pending": "\f17b",
|
||||||
"message-succeeded": "\f17c",
|
"message-read": "\f17c",
|
||||||
"message": "\f17d",
|
"message-succeeded": "\f17d",
|
||||||
"microphone-alt": "\f17e",
|
"message": "\f17e",
|
||||||
"microphone": "\f17f",
|
"microphone-alt": "\f17f",
|
||||||
"monospace": "\f180",
|
"microphone": "\f180",
|
||||||
"more-circle": "\f181",
|
"monospace": "\f181",
|
||||||
"more": "\f182",
|
"more-circle": "\f182",
|
||||||
"move-caption-down": "\f183",
|
"more": "\f183",
|
||||||
"move-caption-up": "\f184",
|
"move-caption-down": "\f184",
|
||||||
"mute": "\f185",
|
"move-caption-up": "\f185",
|
||||||
"muted": "\f186",
|
"mute": "\f186",
|
||||||
"my-notes": "\f187",
|
"muted": "\f187",
|
||||||
"new-chat-filled": "\f188",
|
"my-notes": "\f188",
|
||||||
"next": "\f189",
|
"new-chat-filled": "\f189",
|
||||||
"nochannel": "\f18a",
|
"next": "\f18a",
|
||||||
"noise-suppression": "\f18b",
|
"nochannel": "\f18b",
|
||||||
"non-contacts": "\f18c",
|
"noise-suppression": "\f18c",
|
||||||
"one-filled": "\f18d",
|
"non-contacts": "\f18d",
|
||||||
"open-in-new-tab": "\f18e",
|
"one-filled": "\f18e",
|
||||||
"password-off": "\f18f",
|
"open-in-new-tab": "\f18f",
|
||||||
"pause": "\f190",
|
"password-off": "\f190",
|
||||||
"permissions": "\f191",
|
"pause": "\f191",
|
||||||
"phone-discard-outline": "\f192",
|
"permissions": "\f192",
|
||||||
"phone-discard": "\f193",
|
"phone-discard-outline": "\f193",
|
||||||
"phone": "\f194",
|
"phone-discard": "\f194",
|
||||||
"photo": "\f195",
|
"phone": "\f195",
|
||||||
"pin-badge": "\f196",
|
"photo": "\f196",
|
||||||
"pin-list": "\f197",
|
"pin-badge": "\f197",
|
||||||
"pin": "\f198",
|
"pin-list": "\f198",
|
||||||
"pinned-chat": "\f199",
|
"pin": "\f199",
|
||||||
"pinned-message": "\f19a",
|
"pinned-chat": "\f19a",
|
||||||
"pip": "\f19b",
|
"pinned-message": "\f19b",
|
||||||
"play-story": "\f19c",
|
"pip": "\f19c",
|
||||||
"play": "\f19d",
|
"play-story": "\f19d",
|
||||||
"poll": "\f19e",
|
"play": "\f19e",
|
||||||
"previous": "\f19f",
|
"poll": "\f19f",
|
||||||
"privacy-policy": "\f1a0",
|
"previous": "\f1a0",
|
||||||
"quote-text": "\f1a1",
|
"privacy-policy": "\f1a1",
|
||||||
"quote": "\f1a2",
|
"quote-text": "\f1a2",
|
||||||
"readchats": "\f1a3",
|
"quote": "\f1a3",
|
||||||
"recent": "\f1a4",
|
"readchats": "\f1a4",
|
||||||
"reload": "\f1a5",
|
"recent": "\f1a5",
|
||||||
"remove-quote": "\f1a6",
|
"reload": "\f1a6",
|
||||||
"remove": "\f1a7",
|
"remove-quote": "\f1a7",
|
||||||
"reopen-topic": "\f1a8",
|
"remove": "\f1a8",
|
||||||
"replace": "\f1a9",
|
"reopen-topic": "\f1a9",
|
||||||
"replies": "\f1aa",
|
"replace": "\f1aa",
|
||||||
"reply-filled": "\f1ab",
|
"replies": "\f1ab",
|
||||||
"reply": "\f1ac",
|
"reply-filled": "\f1ac",
|
||||||
"revenue-split": "\f1ad",
|
"reply": "\f1ad",
|
||||||
"revote": "\f1ae",
|
"revenue-split": "\f1ae",
|
||||||
"save-story": "\f1af",
|
"revote": "\f1af",
|
||||||
"saved-messages": "\f1b0",
|
"save-story": "\f1b0",
|
||||||
"schedule": "\f1b1",
|
"saved-messages": "\f1b1",
|
||||||
"search": "\f1b2",
|
"schedule": "\f1b2",
|
||||||
"select": "\f1b3",
|
"search": "\f1b3",
|
||||||
"send-outline": "\f1b4",
|
"select": "\f1b4",
|
||||||
"send": "\f1b5",
|
"send-outline": "\f1b5",
|
||||||
"settings-filled": "\f1b6",
|
"send": "\f1b6",
|
||||||
"settings": "\f1b7",
|
"settings-filled": "\f1b7",
|
||||||
"share-filled": "\f1b8",
|
"settings": "\f1b8",
|
||||||
"share-screen-outlined": "\f1b9",
|
"share-filled": "\f1b9",
|
||||||
"share-screen-stop": "\f1ba",
|
"share-screen-outlined": "\f1ba",
|
||||||
"share-screen": "\f1bb",
|
"share-screen-stop": "\f1bb",
|
||||||
"show-message": "\f1bc",
|
"share-screen": "\f1bc",
|
||||||
"sidebar": "\f1bd",
|
"show-message": "\f1bd",
|
||||||
"skip-next": "\f1be",
|
"sidebar": "\f1be",
|
||||||
"skip-previous": "\f1bf",
|
"skip-next": "\f1bf",
|
||||||
"smallscreen": "\f1c0",
|
"skip-previous": "\f1c0",
|
||||||
"smile": "\f1c1",
|
"smallscreen": "\f1c1",
|
||||||
"sort": "\f1c2",
|
"smile": "\f1c2",
|
||||||
"speaker-muted-story": "\f1c3",
|
"sort": "\f1c3",
|
||||||
"speaker-outline": "\f1c4",
|
"speaker-muted-story": "\f1c4",
|
||||||
"speaker-story": "\f1c5",
|
"speaker-outline": "\f1c5",
|
||||||
"speaker": "\f1c6",
|
"speaker-story": "\f1c6",
|
||||||
"spoiler-disable": "\f1c7",
|
"speaker": "\f1c7",
|
||||||
"spoiler": "\f1c8",
|
"spoiler-disable": "\f1c8",
|
||||||
"sport": "\f1c9",
|
"spoiler": "\f1c9",
|
||||||
"star": "\f1ca",
|
"sport": "\f1ca",
|
||||||
"stars-lock": "\f1cb",
|
"star": "\f1cb",
|
||||||
"stats": "\f1cc",
|
"stars-lock": "\f1cc",
|
||||||
"stealth-future": "\f1cd",
|
"stats": "\f1cd",
|
||||||
"stealth-past": "\f1ce",
|
"stealth-future": "\f1ce",
|
||||||
"stickers": "\f1cf",
|
"stealth-past": "\f1cf",
|
||||||
"stop-raising-hand": "\f1d0",
|
"stickers": "\f1d0",
|
||||||
"stop": "\f1d1",
|
"stop-raising-hand": "\f1d1",
|
||||||
"story-caption": "\f1d2",
|
"stop": "\f1d2",
|
||||||
"story-expired": "\f1d3",
|
"story-caption": "\f1d3",
|
||||||
"story-priority": "\f1d4",
|
"story-expired": "\f1d4",
|
||||||
"story-reply": "\f1d5",
|
"story-priority": "\f1d5",
|
||||||
"strikethrough": "\f1d6",
|
"story-reply": "\f1d6",
|
||||||
"tag-add": "\f1d7",
|
"strikethrough": "\f1d7",
|
||||||
"tag-crossed": "\f1d8",
|
"tag-add": "\f1d8",
|
||||||
"tag-filter": "\f1d9",
|
"tag-crossed": "\f1d9",
|
||||||
"tag-name": "\f1da",
|
"tag-filter": "\f1da",
|
||||||
"tag": "\f1db",
|
"tag-name": "\f1db",
|
||||||
"timer": "\f1dc",
|
"tag": "\f1dc",
|
||||||
"toncoin": "\f1dd",
|
"timer": "\f1dd",
|
||||||
"trade": "\f1de",
|
"toncoin": "\f1de",
|
||||||
"transcribe": "\f1df",
|
"trade": "\f1df",
|
||||||
"truck": "\f1e0",
|
"transcribe": "\f1e0",
|
||||||
"unarchive": "\f1e1",
|
"truck": "\f1e1",
|
||||||
"underlined": "\f1e2",
|
"unarchive": "\f1e2",
|
||||||
"unlock-badge": "\f1e3",
|
"underlined": "\f1e3",
|
||||||
"unlock": "\f1e4",
|
"unlock-badge": "\f1e4",
|
||||||
"unmute": "\f1e5",
|
"unlock": "\f1e5",
|
||||||
"unpin": "\f1e6",
|
"unmute": "\f1e6",
|
||||||
"unread": "\f1e7",
|
"unpin": "\f1e7",
|
||||||
"up": "\f1e8",
|
"unread": "\f1e8",
|
||||||
"user-filled": "\f1e9",
|
"up": "\f1e9",
|
||||||
"user-online": "\f1ea",
|
"user-filled": "\f1ea",
|
||||||
"user": "\f1eb",
|
"user-online": "\f1eb",
|
||||||
"video-outlined": "\f1ec",
|
"user": "\f1ec",
|
||||||
"video-stop": "\f1ed",
|
"video-outlined": "\f1ed",
|
||||||
"video": "\f1ee",
|
"video-stop": "\f1ee",
|
||||||
"view-once": "\f1ef",
|
"video": "\f1ef",
|
||||||
"voice-chat": "\f1f0",
|
"view-once": "\f1f0",
|
||||||
"volume-1": "\f1f1",
|
"voice-chat": "\f1f1",
|
||||||
"volume-2": "\f1f2",
|
"volume-1": "\f1f2",
|
||||||
"volume-3": "\f1f3",
|
"volume-2": "\f1f3",
|
||||||
"web": "\f1f4",
|
"volume-3": "\f1f4",
|
||||||
"webapp": "\f1f5",
|
"web": "\f1f5",
|
||||||
"word-wrap": "\f1f6",
|
"webapp": "\f1f6",
|
||||||
"zoom-in": "\f1f7",
|
"word-wrap": "\f1f7",
|
||||||
"zoom-out": "\f1f8",
|
"zoom-in": "\f1f8",
|
||||||
|
"zoom-out": "\f1f9",
|
||||||
);
|
);
|
||||||
|
|
||||||
.icon-active-sessions::before {
|
.icon-active-sessions::before {
|
||||||
@ -552,6 +553,9 @@ $icons-map: (
|
|||||||
.icon-forward::before {
|
.icon-forward::before {
|
||||||
content: map.get($icons-map, "forward");
|
content: map.get($icons-map, "forward");
|
||||||
}
|
}
|
||||||
|
.icon-fragment::before {
|
||||||
|
content: map.get($icons-map, "fragment");
|
||||||
|
}
|
||||||
.icon-fullscreen::before {
|
.icon-fullscreen::before {
|
||||||
content: map.get($icons-map, "fullscreen");
|
content: map.get($icons-map, "fullscreen");
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@ -88,6 +88,7 @@ export type FontIconName =
|
|||||||
| 'fontsize'
|
| 'fontsize'
|
||||||
| 'forums'
|
| 'forums'
|
||||||
| 'forward'
|
| 'forward'
|
||||||
|
| 'fragment'
|
||||||
| 'fullscreen'
|
| 'fullscreen'
|
||||||
| 'gifs'
|
| 'gifs'
|
||||||
| 'gift'
|
| 'gift'
|
||||||
|
|||||||
28
src/types/language.d.ts
vendored
28
src/types/language.d.ts
vendored
@ -590,10 +590,17 @@ export interface LangPair {
|
|||||||
'ErrorSendRestrictedStickersAll': undefined;
|
'ErrorSendRestrictedStickersAll': undefined;
|
||||||
'ErrorPhoneNumberInvalid': undefined;
|
'ErrorPhoneNumberInvalid': undefined;
|
||||||
'ErrorCodeInvalid': undefined;
|
'ErrorCodeInvalid': undefined;
|
||||||
|
'ErrorEmailCodeInvalid': undefined;
|
||||||
'ErrorIncorrectPassword': undefined;
|
'ErrorIncorrectPassword': undefined;
|
||||||
'ErrorPasswordFlood': undefined;
|
'ErrorPasswordFlood': undefined;
|
||||||
'ErrorPhoneBanned': undefined;
|
'ErrorPhoneBanned': undefined;
|
||||||
'ErrorUnexpected': undefined;
|
'ErrorUnexpected': undefined;
|
||||||
|
'ErrorEmailUnconfirmed': undefined;
|
||||||
|
'ErrorEmailHashExpired': undefined;
|
||||||
|
'ErrorNewSaltInvalid': undefined;
|
||||||
|
'ErrorPasswordChanged': undefined;
|
||||||
|
'ErrorPasswordMissing': undefined;
|
||||||
|
'ErrorUnspecified': undefined;
|
||||||
'NoStickers': undefined;
|
'NoStickers': undefined;
|
||||||
'ClearRecentEmoji': undefined;
|
'ClearRecentEmoji': undefined;
|
||||||
'TextFormatAddLinkTitle': undefined;
|
'TextFormatAddLinkTitle': undefined;
|
||||||
@ -1190,6 +1197,7 @@ export interface LangPair {
|
|||||||
'GiftInfoViewUpgraded': undefined;
|
'GiftInfoViewUpgraded': undefined;
|
||||||
'GiftInfoUpgradeBadge': undefined;
|
'GiftInfoUpgradeBadge': undefined;
|
||||||
'GiftInfoUpgradeForFree': undefined;
|
'GiftInfoUpgradeForFree': undefined;
|
||||||
|
'GiftInfoWithdraw': undefined;
|
||||||
'GiftUpgradeUniqueTitle': undefined;
|
'GiftUpgradeUniqueTitle': undefined;
|
||||||
'GiftUpgradeUniqueDescription': undefined;
|
'GiftUpgradeUniqueDescription': undefined;
|
||||||
'GiftUpgradeTransferableTitle': undefined;
|
'GiftUpgradeTransferableTitle': undefined;
|
||||||
@ -1203,6 +1211,8 @@ export interface LangPair {
|
|||||||
'GiftUpgradedDescription': undefined;
|
'GiftUpgradedDescription': undefined;
|
||||||
'GiftMakeUniqueAcc': undefined;
|
'GiftMakeUniqueAcc': undefined;
|
||||||
'GiftMakeUniqueLink': undefined;
|
'GiftMakeUniqueLink': undefined;
|
||||||
|
'GiftWithdrawTitle': undefined;
|
||||||
|
'GiftWithdrawSubmit': undefined;
|
||||||
'AllGiftsCategory': undefined;
|
'AllGiftsCategory': undefined;
|
||||||
'LimitedGiftsCategory': undefined;
|
'LimitedGiftsCategory': undefined;
|
||||||
'StockGiftsCategory': undefined;
|
'StockGiftsCategory': undefined;
|
||||||
@ -1296,6 +1306,9 @@ export interface LangPair {
|
|||||||
'ViewButtonGiftUnique': undefined;
|
'ViewButtonGiftUnique': undefined;
|
||||||
'AuthContinueOnThisLanguage': undefined;
|
'AuthContinueOnThisLanguage': undefined;
|
||||||
'Share': undefined;
|
'Share': undefined;
|
||||||
|
'CheckPasswordTitle': undefined;
|
||||||
|
'CheckPasswordPlaceholder': undefined;
|
||||||
|
'CheckPasswordDescription': undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LangPairWithVariables<V extends unknown = LangVariable> {
|
export interface LangPairWithVariables<V extends unknown = LangVariable> {
|
||||||
@ -1461,6 +1474,12 @@ export interface LangPairWithVariables<V extends unknown = LangVariable> {
|
|||||||
'SlowModeHint': {
|
'SlowModeHint': {
|
||||||
'time': V;
|
'time': V;
|
||||||
};
|
};
|
||||||
|
'ErrorFloodTime': {
|
||||||
|
'time': V;
|
||||||
|
};
|
||||||
|
'ErrorPasswordFresh': {
|
||||||
|
'time': V;
|
||||||
|
};
|
||||||
'ErrorUnexpectedMessage': {
|
'ErrorUnexpectedMessage': {
|
||||||
'error': V;
|
'error': V;
|
||||||
};
|
};
|
||||||
@ -1707,6 +1726,9 @@ export interface LangPairWithVariables<V extends unknown = LangVariable> {
|
|||||||
'peer': V;
|
'peer': V;
|
||||||
'link': V;
|
'link': V;
|
||||||
};
|
};
|
||||||
|
'GiftWithdrawDescription': {
|
||||||
|
'gift': V;
|
||||||
|
};
|
||||||
'StarsAmount': {
|
'StarsAmount': {
|
||||||
'amount': V;
|
'amount': V;
|
||||||
};
|
};
|
||||||
@ -1829,9 +1851,6 @@ export interface LangPairPluralWithVariables<V extends unknown = LangVariable> {
|
|||||||
'PreviewSenderSendFile': {
|
'PreviewSenderSendFile': {
|
||||||
'count': V;
|
'count': V;
|
||||||
};
|
};
|
||||||
'ErrorFlood': {
|
|
||||||
'hour': V;
|
|
||||||
};
|
|
||||||
'PinnedMessageTitle': {
|
'PinnedMessageTitle': {
|
||||||
'index': V;
|
'index': V;
|
||||||
};
|
};
|
||||||
@ -1958,6 +1977,9 @@ export interface LangPairPluralWithVariables<V extends unknown = LangVariable> {
|
|||||||
'count': V;
|
'count': V;
|
||||||
'total': V;
|
'total': V;
|
||||||
};
|
};
|
||||||
|
'GiftWithdrawWait': {
|
||||||
|
'days': V;
|
||||||
|
};
|
||||||
'StarsAmountText': {
|
'StarsAmountText': {
|
||||||
'amount': V;
|
'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(
|
function processTranslation(
|
||||||
langKey: LangKey,
|
langKey: LangKey,
|
||||||
variables?: Record<string, LangVariable>,
|
variables?: Record<string, LangVariable | RegularLangFnParameters>,
|
||||||
options?: LangFnOptions | LangFnOptionsWithPlural,
|
options?: LangFnOptions | LangFnOptionsWithPlural,
|
||||||
): string {
|
): string {
|
||||||
const cacheKey = `${langKey}-${JSON.stringify(variables)}-${JSON.stringify(options)}`;
|
const cacheKey = `${langKey}-${JSON.stringify(variables)}-${JSON.stringify(options)}`;
|
||||||
@ -377,6 +377,9 @@ function processTranslation(
|
|||||||
const variableEntries = variables ? Object.entries(variables) : [];
|
const variableEntries = variables ? Object.entries(variables) : [];
|
||||||
const finalString = variableEntries.reduce((result, [key, value]) => {
|
const finalString = variableEntries.reduce((result, [key, value]) => {
|
||||||
if (value === undefined) return result;
|
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);
|
const valueAsString = Number.isFinite(value) ? formatters!.number.format(value as number) : String(value);
|
||||||
return result.replace(`{${key}}`, valueAsString);
|
return result.replace(`{${key}}`, valueAsString);
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import type { TextFilter } from '../../components/common/helpers/renderText';
|
|||||||
import type {
|
import type {
|
||||||
LangPairPluralWithVariables,
|
LangPairPluralWithVariables,
|
||||||
LangPairWithVariables,
|
LangPairWithVariables,
|
||||||
|
LangVariable,
|
||||||
PluralLangKey,
|
PluralLangKey,
|
||||||
PluralLangKeyWithVariables,
|
PluralLangKeyWithVariables,
|
||||||
RegularLangKey,
|
RegularLangKey,
|
||||||
@ -55,7 +56,9 @@ type RegularLangFnParametersWithoutVariables = {
|
|||||||
type RegularLangFnParametersWithVariables<T = LangPairWithVariables> = {
|
type RegularLangFnParametersWithVariables<T = LangPairWithVariables> = {
|
||||||
[K in keyof T]: {
|
[K in keyof T]: {
|
||||||
key: K;
|
key: K;
|
||||||
variables: T[K];
|
variables: {
|
||||||
|
[key in keyof T[K]]: LangVariable | RegularLangFnParameters;
|
||||||
|
};
|
||||||
options?: LangFnOptions;
|
options?: LangFnOptions;
|
||||||
}
|
}
|
||||||
}[keyof T];
|
}[keyof T];
|
||||||
@ -69,7 +72,9 @@ type RegularLangFnPluralParameters = {
|
|||||||
type RegularLangFnPluralParametersWithVariables<T = LangPairPluralWithVariables> = {
|
type RegularLangFnPluralParametersWithVariables<T = LangPairPluralWithVariables> = {
|
||||||
[K in keyof T]: {
|
[K in keyof T]: {
|
||||||
key: K;
|
key: K;
|
||||||
variables: T[K];
|
variables: {
|
||||||
|
[key in keyof T[K]]: LangVariable | RegularLangFnParameters;
|
||||||
|
};
|
||||||
options: LangFnOptionsWithPlural;
|
options: LangFnOptionsWithPlural;
|
||||||
}
|
}
|
||||||
}[keyof T];
|
}[keyof T];
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user