Dialog: Migrate messages to new lang API (#6800)
This commit is contained in:
parent
85c6df27b8
commit
aafb84c5e1
@ -1,7 +1,15 @@
|
||||
import type { CallbackAction } from '../../global/types';
|
||||
import type { IconName } from '../../types/icons';
|
||||
import type { LangFnParameters, RegularLangFnParameters } from '../../util/localization';
|
||||
import type { ApiDocument, ApiFormattedText, ApiMessageEntity, ApiPhoto, ApiReaction, ApiVideo } from './messages';
|
||||
import type {
|
||||
ApiContact,
|
||||
ApiDocument,
|
||||
ApiFormattedText,
|
||||
ApiMessageEntity,
|
||||
ApiPhoto,
|
||||
ApiReaction,
|
||||
ApiVideo,
|
||||
} from './messages';
|
||||
import type { ApiPremiumSection } from './payments';
|
||||
import type { ApiBotVerification } from './peers';
|
||||
import type { ApiStarsSubscriptionPricing } from './stars';
|
||||
@ -143,6 +151,27 @@ export type ApiNotification = {
|
||||
messageEntities?: undefined;
|
||||
});
|
||||
|
||||
export type ApiDialogError = {
|
||||
type: 'error';
|
||||
} & ApiError;
|
||||
|
||||
export type ApiDialogMessage = {
|
||||
type: 'message';
|
||||
text: ApiFormattedText;
|
||||
};
|
||||
|
||||
export type ApiDialogContact = {
|
||||
type: 'contact';
|
||||
contact: ApiContact;
|
||||
};
|
||||
|
||||
export type ApiDialogLocalizedMessage = {
|
||||
type: 'localized';
|
||||
text: LangFnParameters;
|
||||
};
|
||||
|
||||
export type ApiDialog = ApiDialogError | ApiDialogMessage | ApiDialogContact | ApiDialogLocalizedMessage;
|
||||
|
||||
export type ApiError = {
|
||||
message: string;
|
||||
entities?: ApiMessageEntity[];
|
||||
|
||||
@ -663,7 +663,8 @@
|
||||
"AttachDocument" = "File";
|
||||
"Poll" = "Poll";
|
||||
"SlowModePlaceholder" = "Next message in {timer}";
|
||||
"SlowModeHint" = "Slow Mode is active. You can send\nyour next message in {time}.";
|
||||
"SlowModeHint" = "Slow Mode is active. You can send your next message in {time}.";
|
||||
"NoVoiceMessagesAllowed" = "**{user}** doesn't accept voice messages.";
|
||||
"SendMessageAsTitle" = "Send message as...";
|
||||
"Message" = "Message";
|
||||
"RecentStickers" = "Recently Used";
|
||||
@ -737,6 +738,8 @@
|
||||
"ErrorPasswordChanged" = "Password has been changed, please try again";
|
||||
"ErrorPasswordMissing" = "You must set 2FA password to use this feature";
|
||||
"ErrorPasskeyUnknown" = "This passkey is not assigned to any account";
|
||||
"ErrorMessageTooLong_one" = "The provided message is too long. Please remove {count} character.";
|
||||
"ErrorMessageTooLong_other" = "The provided message is too long. Please remove {count} characters.";
|
||||
"ErrorUrlExpired" = "This link has expired";
|
||||
"ErrorUnspecified" = "Error";
|
||||
"NoStickers" = "No stickers yet";
|
||||
|
||||
@ -1050,12 +1050,16 @@ const Composer = ({
|
||||
const extraLength = text.length - maxLength;
|
||||
showDialog({
|
||||
data: {
|
||||
message: 'MESSAGE_TOO_LONG_PLEASE_REMOVE_CHARACTERS',
|
||||
textParams: {
|
||||
'{EXTRA_CHARS_COUNT}': extraLength.toString(),
|
||||
'{PLURAL_S}': extraLength > 1 ? 's' : '',
|
||||
type: 'localized',
|
||||
text: {
|
||||
key: 'ErrorMessageTooLong',
|
||||
variables: {
|
||||
count: extraLength,
|
||||
},
|
||||
options: {
|
||||
pluralValue: extraLength,
|
||||
},
|
||||
},
|
||||
hasErrorKey: true,
|
||||
},
|
||||
});
|
||||
|
||||
@ -1080,11 +1084,16 @@ const Composer = ({
|
||||
const secondsRemaining = nextSendDateNotReached
|
||||
? slowMode.nextSendDate! - nowSeconds
|
||||
: slowMode.seconds - secondsSinceLastMessage!;
|
||||
|
||||
showDialog({
|
||||
data: {
|
||||
message: oldLang('SlowModeHint', formatMediaDuration(secondsRemaining)),
|
||||
isSlowMode: true,
|
||||
hasErrorKey: false,
|
||||
type: 'localized',
|
||||
text: {
|
||||
key: 'SlowModeHint',
|
||||
variables: {
|
||||
time: formatMediaDuration(secondsRemaining),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -733,7 +733,7 @@ function processEntityAsHtml(
|
||||
case ApiMessageEntityTypes.TextUrl:
|
||||
return `<a
|
||||
class="text-entity-link"
|
||||
href=${getLinkUrl(rawEntityText, entity)}
|
||||
href="${getLinkUrl(rawEntityText, entity)}"
|
||||
data-entity-type="${entity.type}"
|
||||
dir="auto"
|
||||
>${renderedContent}</a>`;
|
||||
|
||||
@ -1,8 +1,13 @@
|
||||
import type { TeactNode } from '../../lib/teact/teact';
|
||||
import { memo, useEffect } from '../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../global';
|
||||
|
||||
import type {
|
||||
ApiContact, ApiError,
|
||||
ApiContact,
|
||||
ApiDialog,
|
||||
ApiDialogError,
|
||||
ApiDialogLocalizedMessage,
|
||||
ApiDialogMessage,
|
||||
} from '../../api/types';
|
||||
import type { MessageList } from '../../types';
|
||||
|
||||
@ -18,7 +23,7 @@ import Modal from '../ui/Modal';
|
||||
|
||||
type StateProps = {
|
||||
currentMessageList?: MessageList;
|
||||
dialogs: (ApiError | ApiContact)[];
|
||||
dialogs: ApiDialog[];
|
||||
};
|
||||
|
||||
const Dialogs = ({ dialogs, currentMessageList }: StateProps) => {
|
||||
@ -81,17 +86,16 @@ const Dialogs = ({ dialogs, currentMessageList }: StateProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
const renderError = (error: ApiError) => {
|
||||
const renderTextDialog = (renderedText: TeactNode, title = 'Telegram') => {
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isModalOpen}
|
||||
onClose={closeModal}
|
||||
onCloseAnimationEnd={dismissDialog}
|
||||
className="error"
|
||||
title={getErrorHeader(error)}
|
||||
title={title}
|
||||
>
|
||||
{error.hasErrorKey ? getReadableErrorText(error)
|
||||
: renderTextWithEntities({ text: error.message, entities: error.entities })}
|
||||
{renderedText}
|
||||
<div className="dialog-buttons mt-2">
|
||||
<Button isText onClick={closeModal}>{lang('OK')}</Button>
|
||||
</div>
|
||||
@ -99,9 +103,37 @@ const Dialogs = ({ dialogs, currentMessageList }: StateProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
const renderDialog = (dialog: ApiError | ApiContact) => {
|
||||
if ('phoneNumber' in dialog) {
|
||||
return renderContactRequest(dialog);
|
||||
const renderFormattedTextDialog = (dialog: ApiDialogMessage, title?: string) => {
|
||||
const renderedText = renderTextWithEntities(dialog.text);
|
||||
|
||||
return renderTextDialog(renderedText, title);
|
||||
};
|
||||
|
||||
const renderLocalizedDialog = (dialog: ApiDialogLocalizedMessage, title?: string) => {
|
||||
return renderTextDialog(lang.with(dialog.text), title);
|
||||
};
|
||||
|
||||
const renderError = (error: ApiDialogError) => {
|
||||
const renderedErrorMessage = error.hasErrorKey
|
||||
? getReadableErrorText(error)
|
||||
: error.entities?.length
|
||||
? renderTextWithEntities({ text: error.message, entities: error.entities })
|
||||
: error.message;
|
||||
|
||||
return renderTextDialog(renderedErrorMessage, getErrorHeader(error));
|
||||
};
|
||||
|
||||
const renderDialog = (dialog: ApiDialog) => {
|
||||
if (dialog.type === 'contact') {
|
||||
return renderContactRequest(dialog.contact);
|
||||
}
|
||||
|
||||
if (dialog.type === 'message') {
|
||||
return renderFormattedTextDialog(dialog);
|
||||
}
|
||||
|
||||
if (dialog.type === 'localized') {
|
||||
return renderLocalizedDialog(dialog);
|
||||
}
|
||||
|
||||
return renderError(dialog);
|
||||
@ -110,7 +142,7 @@ const Dialogs = ({ dialogs, currentMessageList }: StateProps) => {
|
||||
return Boolean(dialogs.length) && renderDialog(dialogs[dialogs.length - 1]);
|
||||
};
|
||||
|
||||
function getErrorHeader(error: ApiError) {
|
||||
function getErrorHeader(error: ApiDialogError) {
|
||||
if (error.isSlowMode) {
|
||||
return 'Slowmode enabled';
|
||||
}
|
||||
|
||||
@ -71,7 +71,10 @@ const SponsoredMessageContextMenuContainer: FC<OwnProps> = ({
|
||||
const handleSponsorInfo = useLastCallback(() => {
|
||||
showDialog({
|
||||
data: {
|
||||
message: [sponsorInfo, additionalInfo].filter(Boolean).join('\n'),
|
||||
type: 'message',
|
||||
text: {
|
||||
text: [sponsorInfo, additionalInfo].filter(Boolean).join('\n'),
|
||||
},
|
||||
},
|
||||
});
|
||||
handleItemClick();
|
||||
|
||||
@ -402,8 +402,9 @@
|
||||
user-select: none;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
align-items: center;
|
||||
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
@ -428,10 +429,8 @@
|
||||
|
||||
.sender-boosts {
|
||||
user-select: none;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@ import type {
|
||||
} from '../../types';
|
||||
import {
|
||||
type ApiChat,
|
||||
type ApiContact,
|
||||
type ApiInputMessageReplyInfo,
|
||||
type ApiPeer,
|
||||
type ApiUrlAuthResult,
|
||||
@ -138,11 +137,15 @@ addActionHandler('clickBotInlineButton', (global, actions, payload): ActionRetur
|
||||
}
|
||||
actions.showDialog({
|
||||
data: {
|
||||
phoneNumber: user.phoneNumber,
|
||||
firstName: user.firstName || '',
|
||||
lastName: user.lastName || '',
|
||||
userId: user.id,
|
||||
} as ApiContact,
|
||||
type: 'contact',
|
||||
contact: {
|
||||
mediaType: 'contact',
|
||||
phoneNumber: user.phoneNumber,
|
||||
firstName: user.firstName || '',
|
||||
lastName: user.lastName || '',
|
||||
userId: user.id,
|
||||
},
|
||||
},
|
||||
tabId,
|
||||
});
|
||||
break;
|
||||
@ -1438,7 +1441,7 @@ async function answerCallbackButton<T extends GlobalState>(
|
||||
const { message, alert: isError, url } = result;
|
||||
|
||||
if (isError) {
|
||||
showDialog({ data: { message: message || 'Error' }, tabId });
|
||||
showDialog({ data: { type: 'error', message: message || 'Error' }, tabId });
|
||||
} else if (message) {
|
||||
showNotification({ message, tabId });
|
||||
} else if (url) {
|
||||
|
||||
@ -789,7 +789,7 @@ addActionHandler('createChannel', async (global, actions, payload): Promise<void
|
||||
if ((error as ApiError).message === 'CHANNELS_TOO_MUCH') {
|
||||
actions.openLimitReachedModal({ limit: 'channels', tabId });
|
||||
} else {
|
||||
actions.showDialog({ data: { ...(error as ApiError), hasErrorKey: true }, tabId });
|
||||
actions.showDialog({ data: { type: 'error', ...(error as ApiError), hasErrorKey: true }, tabId });
|
||||
}
|
||||
}
|
||||
|
||||
@ -847,7 +847,7 @@ addActionHandler('joinChannel', async (global, actions, payload): Promise<void>
|
||||
if ((error as ApiError).message === 'CHANNELS_TOO_MUCH') {
|
||||
actions.openLimitReachedModal({ limit: 'channels', tabId });
|
||||
} else {
|
||||
actions.showDialog({ data: { ...(error as ApiError), hasErrorKey: true }, tabId });
|
||||
actions.showDialog({ data: { type: 'error', ...(error as ApiError), hasErrorKey: true }, tabId });
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -2651,7 +2651,7 @@ addActionHandler('toggleForum', async (global, actions, payload): Promise<void>
|
||||
if ((error as ApiError).message === 'FLOOD') {
|
||||
actions.showNotification({ message: langProvider.oldTranslate('FloodWait'), tabId });
|
||||
} else {
|
||||
actions.showDialog({ data: { ...(error as ApiError), hasErrorKey: true }, tabId });
|
||||
actions.showDialog({ data: { type: 'error', ...(error as ApiError), hasErrorKey: true }, tabId });
|
||||
}
|
||||
}
|
||||
|
||||
@ -2860,7 +2860,7 @@ addActionHandler('joinChatlistInvite', async (global, actions, payload): Promise
|
||||
if ((error as ApiError).message === 'CHATLISTS_TOO_MUCH') {
|
||||
actions.openLimitReachedModal({ limit: 'chatlistJoined', tabId });
|
||||
} else {
|
||||
actions.showDialog({ data: { ...(error as ApiError), hasErrorKey: true }, tabId });
|
||||
actions.showDialog({ data: { type: 'error', ...(error as ApiError), hasErrorKey: true }, tabId });
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -2946,7 +2946,7 @@ addActionHandler('createChatlistInvite', async (global, actions, payload): Promi
|
||||
actions.openLimitReachedModal({ limit: 'chatlistInvites', tabId });
|
||||
actions.openSettingsScreen({ screen: SettingsScreens.Folders, tabId });
|
||||
} else {
|
||||
actions.showDialog({ data: { ...(error as ApiError), hasErrorKey: true }, tabId });
|
||||
actions.showDialog({ data: { type: 'error', ...(error as ApiError), hasErrorKey: true }, tabId });
|
||||
}
|
||||
}
|
||||
|
||||
@ -3031,7 +3031,7 @@ addActionHandler('editChatlistInvite', async (global, actions, payload): Promise
|
||||
};
|
||||
setGlobal(global);
|
||||
} catch (error) {
|
||||
actions.showDialog({ data: { ...(error as ApiError), hasErrorKey: true }, tabId });
|
||||
actions.showDialog({ data: { type: 'error', ...(error as ApiError), hasErrorKey: true }, tabId });
|
||||
} finally {
|
||||
global = getGlobal();
|
||||
|
||||
@ -3532,7 +3532,7 @@ export async function migrateChat<T extends GlobalState>(
|
||||
if ((error as ApiError).message === 'CHANNELS_TOO_MUCH') {
|
||||
actions.openLimitReachedModal({ limit: 'channels', tabId });
|
||||
} else {
|
||||
actions.showDialog({ data: { ...(error as ApiError), hasErrorKey: true }, tabId });
|
||||
actions.showDialog({ data: { type: 'error', ...(error as ApiError), hasErrorKey: true }, tabId });
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
@ -2567,7 +2567,17 @@ addActionHandler('setForwardChatOrTopic', async (global, actions, payload): Prom
|
||||
if (isSelectForwardsContainVoiceMessages && user && !await checkIfVoiceMessagesAllowed(global, user, chatId)) {
|
||||
actions.showDialog({
|
||||
data: {
|
||||
message: oldTranslate('VoiceMessagesRestrictedByPrivacy', getUserFullName(user)),
|
||||
type: 'localized',
|
||||
text: {
|
||||
key: 'NoVoiceMessagesAllowed',
|
||||
variables: {
|
||||
user: getUserFullName(user),
|
||||
},
|
||||
options: {
|
||||
withNodes: true,
|
||||
withMarkdown: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
tabId,
|
||||
});
|
||||
|
||||
@ -1329,5 +1329,5 @@ function handlePaymentFormError(error: string, tabId: number) {
|
||||
return;
|
||||
}
|
||||
|
||||
getActions().showDialog({ data: { message: error, hasErrorKey: true }, tabId });
|
||||
getActions().showDialog({ data: { type: 'error', message: error, hasErrorKey: true }, tabId });
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
||||
} else if (shouldClosePaymentModal(update.error)) {
|
||||
actions.closePaymentModal({ tabId });
|
||||
} else if (actions.showDialog) {
|
||||
actions.showDialog({ data: update.error, tabId });
|
||||
actions.showDialog({ data: { type: 'error', ...update.error }, tabId });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { addCallback } from '../../../lib/teact/teactn';
|
||||
|
||||
import type { ActionReturnType, GlobalState } from '../../types';
|
||||
import { type ApiError } from '../../../api/types';
|
||||
|
||||
import {
|
||||
ANIMATION_WAVE_MIN_INTERVAL,
|
||||
@ -389,13 +388,15 @@ addActionHandler('showDialog', (global, actions, payload): ActionReturnType => {
|
||||
const { data, tabId = getCurrentTabId() } = payload;
|
||||
|
||||
// Filter out errors that we don't want to show to the user
|
||||
if ('message' in data && data.hasErrorKey && !getReadableErrorText(data)) {
|
||||
if (data.type === 'error' && data.hasErrorKey && !getReadableErrorText(data)) {
|
||||
return global;
|
||||
}
|
||||
|
||||
const newDialogs = [...selectTabState(global, tabId).dialogs];
|
||||
if ('message' in data) {
|
||||
const existingErrorIndex = newDialogs.findIndex((err) => (err as ApiError).message === data.message);
|
||||
if (data.type === 'error') {
|
||||
const existingErrorIndex = newDialogs.findIndex((dialog) => {
|
||||
return dialog.type === 'error' && dialog.message === data.message;
|
||||
});
|
||||
if (existingErrorIndex !== -1) {
|
||||
newDialogs.splice(existingErrorIndex, 1);
|
||||
}
|
||||
|
||||
@ -10,9 +10,8 @@ import type {
|
||||
ApiChatType,
|
||||
ApiCheckedGiftCode,
|
||||
ApiCollectibleInfo,
|
||||
ApiContact,
|
||||
ApiDialog,
|
||||
ApiEmojiStatusCollectible,
|
||||
ApiError,
|
||||
ApiFormattedText,
|
||||
ApiGeoPoint,
|
||||
ApiGlobalMessageSearchType,
|
||||
@ -490,7 +489,7 @@ export type TabState = {
|
||||
};
|
||||
|
||||
notifications: ApiNotification[];
|
||||
dialogs: (ApiError | ApiContact)[];
|
||||
dialogs: ApiDialog[];
|
||||
|
||||
safeLinkModalUrl?: string;
|
||||
mapModal?: {
|
||||
|
||||
6
src/types/language.d.ts
vendored
6
src/types/language.d.ts
vendored
@ -2222,6 +2222,9 @@ export interface LangPairWithVariables<V = LangVariable> {
|
||||
'SlowModeHint': {
|
||||
'time': V;
|
||||
};
|
||||
'NoVoiceMessagesAllowed': {
|
||||
'user': V;
|
||||
};
|
||||
'ErrorFloodTime': {
|
||||
'time': V;
|
||||
};
|
||||
@ -3663,6 +3666,9 @@ export interface LangPairPluralWithVariables<V = LangVariable> {
|
||||
'PreviewSenderSendFile': {
|
||||
'count': V;
|
||||
};
|
||||
'ErrorMessageTooLong': {
|
||||
'count': V;
|
||||
};
|
||||
'PinnedMessageTitle': {
|
||||
'index': V;
|
||||
};
|
||||
|
||||
@ -86,7 +86,7 @@ if (IS_SERVICE_WORKER_SUPPORTED) {
|
||||
}
|
||||
|
||||
if (!IS_IOS && !IS_ANDROID && !IS_TEST) {
|
||||
getActions().showDialog?.({ data: { message: 'SERVICE_WORKER_DISABLED', hasErrorKey: true } });
|
||||
getActions().showDialog?.({ data: { type: 'error', message: 'SERVICE_WORKER_DISABLED', hasErrorKey: true } });
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user