Support chat links (#4469)

This commit is contained in:
Alexander Zinchuk 2024-04-19 13:38:21 +04:00
parent 3c4196679a
commit b9ed982170
14 changed files with 183 additions and 43 deletions

View File

@ -2,6 +2,7 @@ import { Api as GramJs } from '../../../lib/gramjs';
import type { ApiPrivacyKey } from '../../../types'; import type { ApiPrivacyKey } from '../../../types';
import type { import type {
ApiChatLink,
ApiConfig, ApiCountry, ApiLangString, ApiConfig, ApiCountry, ApiLangString,
ApiPeerColors, ApiPeerColors,
ApiSession, ApiTimezone, ApiUrlAuthResult, ApiWallpaper, ApiWebSession, ApiSession, ApiTimezone, ApiUrlAuthResult, ApiWallpaper, ApiWebSession,
@ -11,7 +12,7 @@ import { buildCollectionByCallback, omit, pick } from '../../../util/iteratees';
import { getServerTime } from '../../../util/serverTime'; import { getServerTime } from '../../../util/serverTime';
import { addUserToLocalDb } from '../helpers'; import { addUserToLocalDb } from '../helpers';
import { omitVirtualClassFields } from './helpers'; import { omitVirtualClassFields } from './helpers';
import { buildApiDocument } from './messageContent'; import { buildApiDocument, buildMessageTextContent } from './messageContent';
import { buildApiPeerId, getApiChatIdFromMtpPeer } from './peers'; import { buildApiPeerId, getApiChatIdFromMtpPeer } from './peers';
import { buildApiReaction } from './reactions'; import { buildApiReaction } from './reactions';
import { buildApiUser } from './users'; import { buildApiUser } from './users';
@ -261,3 +262,11 @@ export function buildApiTimezone(timezone: GramJs.TypeTimezone): ApiTimezone {
utcOffset, utcOffset,
}; };
} }
export function buildApiChatLink(data: GramJs.account.ResolvedBusinessChatLinks): ApiChatLink {
const chatId = getApiChatIdFromMtpPeer(data.peer);
return {
chatId,
text: buildMessageTextContent(data.message, data.entities),
};
}

View File

@ -5,6 +5,9 @@ import type {
ApiPeer, ApiPhoto, ApiReportReason, ApiPeer, ApiPhoto, ApiReportReason,
} from '../../types'; } from '../../types';
import { buildApiChatFromPreview } from '../apiBuilders/chats';
import { buildApiChatLink } from '../apiBuilders/misc';
import { buildApiUser } from '../apiBuilders/users';
import { buildInputPeer, buildInputPhoto, buildInputReportReason } from '../gramjsBuilders'; import { buildInputPeer, buildInputPhoto, buildInputReportReason } from '../gramjsBuilders';
import { invokeRequest } from './client'; import { invokeRequest } from './client';
@ -71,3 +74,23 @@ export async function changeSessionTtl({
return result; return result;
} }
export async function resolveBusinessChatLink({ slug } : { slug: string }) {
const result = await invokeRequest(new GramJs.account.ResolveBusinessChatLink({
slug,
}), {
shouldIgnoreErrors: true,
});
if (!result) return undefined;
const users = result.users.map(buildApiUser).filter(Boolean);
const chats = result.chats.map((c) => buildApiChatFromPreview(c)).filter(Boolean);
const chatLink = buildApiChatLink(result);
return {
users,
chats,
chatLink,
};
}

View File

@ -3,9 +3,7 @@ export {
setForceHttpTransport, setShouldDebugExportedSenders, setAllowHttpTransport, requestChannelDifference, setForceHttpTransport, setShouldDebugExportedSenders, setAllowHttpTransport, requestChannelDifference,
} from './client'; } from './client';
export { export * from './account';
reportPeer, reportProfilePhoto, changeSessionSettings, changeSessionTtl,
} from './account';
export { export {
provideAuthPhoneNumber, provideAuthCode, provideAuthPassword, provideAuthRegistration, restartAuth, restartAuthWithQr, provideAuthPhoneNumber, provideAuthCode, provideAuthPassword, provideAuthRegistration, restartAuth, restartAuthWithQr,

View File

@ -1,7 +1,7 @@
import type { ThreadId } from '../../types'; import type { ThreadId } from '../../types';
import type { ApiBotCommand } from './bots'; import type { ApiBotCommand } from './bots';
import type { import type {
ApiChatReactions, ApiPhoto, ApiStickerSet, ApiChatReactions, ApiFormattedText, ApiPhoto, ApiStickerSet,
} from './messages'; } from './messages';
import type { ApiChatInviteImporter } from './misc'; import type { ApiChatInviteImporter } from './misc';
import type { import type {
@ -284,3 +284,8 @@ export interface ApiMissingInvitedUser {
isRequiringPremiumToInvite?: boolean; isRequiringPremiumToInvite?: boolean;
isRequiringPremiumToMessage?: boolean; isRequiringPremiumToMessage?: boolean;
} }
export interface ApiChatLink {
chatId: string;
text: ApiFormattedText;
}

View File

@ -76,8 +76,8 @@ import {
selectIsRightColumnShown, selectIsRightColumnShown,
selectNewestMessageWithBotKeyboardButtons, selectNewestMessageWithBotKeyboardButtons,
selectPeerStory, selectPeerStory,
selectRequestedDraft,
selectRequestedDraftFiles, selectRequestedDraftFiles,
selectRequestedDraftText,
selectScheduledIds, selectScheduledIds,
selectTabState, selectTabState,
selectTheme, selectTheme,
@ -99,7 +99,6 @@ import { IS_IOS, IS_VOICE_RECORDING_SUPPORTED } from '../../util/windowEnvironme
import windowSize from '../../util/windowSize'; import windowSize from '../../util/windowSize';
import applyIosAutoCapitalizationFix from '../middle/composer/helpers/applyIosAutoCapitalizationFix'; import applyIosAutoCapitalizationFix from '../middle/composer/helpers/applyIosAutoCapitalizationFix';
import buildAttachment, { prepareAttachmentsToSend } from '../middle/composer/helpers/buildAttachment'; import buildAttachment, { prepareAttachmentsToSend } from '../middle/composer/helpers/buildAttachment';
import { escapeHtml } from '../middle/composer/helpers/cleanHtml';
import { buildCustomEmojiHtml } from '../middle/composer/helpers/customEmoji'; import { buildCustomEmojiHtml } from '../middle/composer/helpers/customEmoji';
import { isSelectionInsideInput } from '../middle/composer/helpers/selection'; import { isSelectionInsideInput } from '../middle/composer/helpers/selection';
import { getPeerColorClass } from './helpers/peerColor'; import { getPeerColorClass } from './helpers/peerColor';
@ -228,7 +227,7 @@ type StateProps =
sendAsChat?: ApiChat; sendAsChat?: ApiChat;
sendAsId?: string; sendAsId?: string;
editingDraft?: ApiFormattedText; editingDraft?: ApiFormattedText;
requestedDraftText?: string; requestedDraft?: ApiFormattedText;
requestedDraftFiles?: File[]; requestedDraftFiles?: File[];
attachBots: GlobalState['attachMenu']['bots']; attachBots: GlobalState['attachMenu']['bots'];
attachMenuPeerType?: ApiAttachMenuPeerType; attachMenuPeerType?: ApiAttachMenuPeerType;
@ -332,7 +331,7 @@ const Composer: FC<OwnProps & StateProps> = ({
sendAsChat, sendAsChat,
sendAsId, sendAsId,
editingDraft, editingDraft,
requestedDraftText, requestedDraft,
requestedDraftFiles, requestedDraftFiles,
botMenuButton, botMenuButton,
attachBots, attachBots,
@ -691,7 +690,7 @@ const Composer: FC<OwnProps & StateProps> = ({
getHtml, getHtml,
setHtml, setHtml,
editedMessage: editingMessage, editedMessage: editingMessage,
isDisabled: isInStoryViewer, isDisabled: isInStoryViewer || Boolean(requestedDraft),
}); });
const resetComposer = useLastCallback((shouldPreserveInput = false) => { const resetComposer = useLastCallback((shouldPreserveInput = false) => {
@ -1080,8 +1079,8 @@ const Composer: FC<OwnProps & StateProps> = ({
}, [contentToBeScheduled, currentMessageList, handleMessageSchedule, requestCalendar]); }, [contentToBeScheduled, currentMessageList, handleMessageSchedule, requestCalendar]);
useEffect(() => { useEffect(() => {
if (requestedDraftText) { if (requestedDraft) {
setHtml(escapeHtml(requestedDraftText)); insertFormattedTextAndUpdateCursor(requestedDraft);
resetOpenChatWithDraft(); resetOpenChatWithDraft();
requestNextMutation(() => { requestNextMutation(() => {
@ -1089,7 +1088,7 @@ const Composer: FC<OwnProps & StateProps> = ({
focusEditableElement(messageInput, true); focusEditableElement(messageInput, true);
}); });
} }
}, [editableInputId, requestedDraftText, resetOpenChatWithDraft, setHtml]); }, [editableInputId, requestedDraft, resetOpenChatWithDraft, setHtml]);
useEffect(() => { useEffect(() => {
if (requestedDraftFiles?.length) { if (requestedDraftFiles?.length) {
@ -1987,7 +1986,7 @@ export default memo(withGlobal<OwnProps>(
); );
const sendAsUser = sendAsId ? selectUser(global, sendAsId) : undefined; const sendAsUser = sendAsId ? selectUser(global, sendAsId) : undefined;
const sendAsChat = !sendAsUser && sendAsId ? selectChat(global, sendAsId) : undefined; const sendAsChat = !sendAsUser && sendAsId ? selectChat(global, sendAsId) : undefined;
const requestedDraftText = selectRequestedDraftText(global, chatId); const requestedDraft = selectRequestedDraft(global, chatId);
const requestedDraftFiles = selectRequestedDraftFiles(global, chatId); const requestedDraftFiles = selectRequestedDraftFiles(global, chatId);
const tabState = selectTabState(global); const tabState = selectTabState(global);
@ -2064,7 +2063,7 @@ export default memo(withGlobal<OwnProps>(
sendAsChat, sendAsChat,
sendAsId, sendAsId,
editingDraft, editingDraft,
requestedDraftText, requestedDraft,
requestedDraftFiles, requestedDraftFiles,
attachBots: global.attachMenu.bots, attachBots: global.attachMenu.bots,
attachMenuPeerType: selectChatType(global, chatId), attachMenuPeerType: selectChatType(global, chatId),

View File

@ -53,7 +53,7 @@ const InviteLink: FC<OwnProps> = ({
}); });
const handleShare = useLastCallback(() => { const handleShare = useLastCallback(() => {
openChatWithDraft({ text: link }); openChatWithDraft({ text: { text: link } });
}); });
const PrimaryLinkMenuButton: FC<{ onTrigger: () => void; isOpen?: boolean }> = useMemo(() => { const PrimaryLinkMenuButton: FC<{ onTrigger: () => void; isOpen?: boolean }> = useMemo(() => {

View File

@ -341,7 +341,9 @@ addActionHandler('switchBotInline', (global, actions, payload): ActionReturnType
} }
actions.openChatWithDraft({ actions.openChatWithDraft({
text: `@${botSender.usernames![0].username} ${query}`, text: {
text: `@${botSender.usernames![0].username} ${query}`,
},
chatId: isSamePeer ? chat.id : undefined, chatId: isSamePeer ? chat.id : undefined,
filter, filter,
tabId, tabId,

View File

@ -1235,7 +1235,7 @@ addActionHandler('openChatByInvite', async (global, actions, payload): Promise<v
addActionHandler('openChatByPhoneNumber', async (global, actions, payload): Promise<void> => { addActionHandler('openChatByPhoneNumber', async (global, actions, payload): Promise<void> => {
const { const {
phoneNumber, startAttach, attach, tabId = getCurrentTabId(), phoneNumber, startAttach, attach, text, tabId = getCurrentTabId(),
} = payload!; } = payload!;
// Open temporary empty chat to make the click response feel faster // Open temporary empty chat to make the click response feel faster
@ -1251,7 +1251,11 @@ addActionHandler('openChatByPhoneNumber', async (global, actions, payload): Prom
return; return;
} }
actions.openChat({ id: chat.id, tabId }); if (text) {
actions.openChatWithDraft({ chatId: chat.id, text: { text }, tabId });
} else {
actions.openChat({ id: chat.id, tabId });
}
if (attach) { if (attach) {
global = getGlobal(); global = getGlobal();
@ -1317,6 +1321,7 @@ addActionHandler('openTelegramLink', (global, actions, payload): ActionReturnTyp
phoneNumber: part1.substr(1, part1.length - 1), phoneNumber: part1.substr(1, part1.length - 1),
startAttach: params.startattach, startAttach: params.startattach,
attach: params.attach, attach: params.attach,
text: params.text,
tabId, tabId,
}); });
return; return;
@ -1481,7 +1486,7 @@ addActionHandler('acceptInviteConfirmation', async (global, actions, payload): P
addActionHandler('openChatByUsername', async (global, actions, payload): Promise<void> => { addActionHandler('openChatByUsername', async (global, actions, payload): Promise<void> => {
const { const {
username, messageId, commentId, startParam, startAttach, attach, threadId, originalParts, startApp, username, messageId, commentId, startParam, startAttach, attach, threadId, originalParts, startApp, text,
tabId = getCurrentTabId(), tabId = getCurrentTabId(),
} = payload!; } = payload!;
@ -1499,7 +1504,15 @@ addActionHandler('openChatByUsername', async (global, actions, payload): Promise
} }
if (!isWebApp) { if (!isWebApp) {
await openChatByUsername( await openChatByUsername(
global, actions, username, threadId, messageId, startParam, startAttach, attach, tabId, global, actions, {
username,
threadId,
channelPostId: messageId,
startParam,
startAttach,
attach,
text,
}, tabId,
); );
return; return;
} }
@ -2643,6 +2656,31 @@ addActionHandler('toggleChannelRecommendations', (global, actions, payload): Act
setGlobal(global); setGlobal(global);
}); });
addActionHandler('resolveBusinessChatLink', async (global, actions, payload): Promise<void> => {
const { slug, tabId = getCurrentTabId() } = payload;
const result = await callApi('resolveBusinessChatLink', { slug });
if (!result) {
actions.showNotification({
message: langProvider.translate('BusinessLink.ErrorExpired'),
tabId,
});
return;
}
const { users, chats, chatLink } = result;
global = getGlobal();
global = addUsers(global, buildCollectionByKey(users, 'id'));
global = addChats(global, buildCollectionByKey(chats, 'id'));
setGlobal(global);
actions.openChatWithDraft({
chatId: chatLink.chatId,
text: chatLink.text,
tabId,
});
});
async function loadChats( async function loadChats(
listType: ChatListType, listType: ChatListType,
offsetId?: string, offsetId?: string,
@ -2944,14 +2982,20 @@ async function getAttachBotOrNotify<T extends GlobalState>(
async function openChatByUsername<T extends GlobalState>( async function openChatByUsername<T extends GlobalState>(
global: T, global: T,
actions: RequiredGlobalActions, actions: RequiredGlobalActions,
username: string, params: {
threadId?: ThreadId, username: string;
channelPostId?: number, threadId?: ThreadId;
startParam?: string, channelPostId?: number;
startAttach?: string, startParam?: string;
attach?: string, startAttach?: string;
attach?: string;
text?: string;
},
...[tabId = getCurrentTabId()]: TabArgs<T> ...[tabId = getCurrentTabId()]: TabArgs<T>
) { ) {
const {
username, threadId, channelPostId, startParam, startAttach, attach, text,
} = params;
global = getGlobal(); global = getGlobal();
const currentChat = selectCurrentChat(global, tabId); const currentChat = selectCurrentChat(global, tabId);
@ -3004,6 +3048,10 @@ async function openChatByUsername<T extends GlobalState>(
global = getGlobal(); global = getGlobal();
openAttachMenuFromLink(global, actions, chat.id, attach, startAttach, tabId); openAttachMenuFromLink(global, actions, chat.id, attach, startAttach, tabId);
} }
if (text) {
actions.openChatWithDraft({ chatId: chat.id, text: { text }, tabId });
}
} }
async function openAttachMenuFromLink<T extends GlobalState>( async function openAttachMenuFromLink<T extends GlobalState>(

View File

@ -221,7 +221,7 @@ export function selectSendAs<T extends GlobalState>(global: T, chatId: string) {
return selectUser(global, id) || selectChat(global, id); return selectUser(global, id) || selectChat(global, id);
} }
export function selectRequestedDraftText<T extends GlobalState>( export function selectRequestedDraft<T extends GlobalState>(
global: T, chatId: string, global: T, chatId: string,
...[tabId = getCurrentTabId()]: TabArgs<T> ...[tabId = getCurrentTabId()]: TabArgs<T>
) { ) {

View File

@ -559,7 +559,7 @@ export type TabState = {
requestedDraft?: { requestedDraft?: {
chatId?: string; chatId?: string;
text: string; text: ApiFormattedText;
files?: File[]; files?: File[];
filter?: ApiChatType[]; filter?: ApiChatType[];
}; };
@ -1323,6 +1323,7 @@ export interface ActionPayloads {
phoneNumber: string; phoneNumber: string;
startAttach?: string | boolean; startAttach?: string | boolean;
attach?: string; attach?: string;
text?: string;
} & WithTabId; } & WithTabId;
openChatByInvite: { openChatByInvite: {
hash: string; hash: string;
@ -1500,6 +1501,9 @@ export interface ActionPayloads {
openTelegramLink: { openTelegramLink: {
url: string; url: string;
} & WithTabId; } & WithTabId;
resolveBusinessChatLink: {
slug: string;
} & WithTabId;
openChatByUsername: { openChatByUsername: {
username: string; username: string;
threadId?: ThreadId; threadId?: ThreadId;
@ -1509,6 +1513,7 @@ export interface ActionPayloads {
startAttach?: string; startAttach?: string;
attach?: string; attach?: string;
startApp?: string; startApp?: string;
text?: string;
originalParts?: string[]; originalParts?: string[];
} & WithTabId; } & WithTabId;
processBoostParameters: { processBoostParameters: {
@ -1967,7 +1972,7 @@ export interface ActionPayloads {
openChatWithDraft: { openChatWithDraft: {
chatId?: string; chatId?: string;
threadId?: ThreadId; threadId?: ThreadId;
text: string; text: ApiFormattedText;
files?: File[]; files?: File[];
filter?: ApiChatType[]; filter?: ApiChatType[];
} & WithTabId; } & WithTabId;

View File

@ -1344,6 +1344,7 @@ account.updateEmojiStatus#fbd3de6b emoji_status:EmojiStatus = Bool;
account.getRecentEmojiStatuses#f578105 hash:long = account.EmojiStatuses; account.getRecentEmojiStatuses#f578105 hash:long = account.EmojiStatuses;
account.reorderUsernames#ef500eab order:Vector<string> = Bool; account.reorderUsernames#ef500eab order:Vector<string> = Bool;
account.toggleUsername#58d6b376 username:string active:Bool = Bool; account.toggleUsername#58d6b376 username:string active:Bool = Bool;
account.resolveBusinessChatLink#5492e5ee slug:string = account.ResolvedBusinessChatLinks;
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>; users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
users.getFullUser#b60f5918 id:InputUser = users.UserFull; users.getFullUser#b60f5918 id:InputUser = users.UserFull;
contacts.getContacts#5dd69e12 hash:long = contacts.Contacts; contacts.getContacts#5dd69e12 hash:long = contacts.Contacts;

View File

@ -58,6 +58,7 @@
"account.getRecentEmojiStatuses", "account.getRecentEmojiStatuses",
"account.reorderUsernames", "account.reorderUsernames",
"account.toggleUsername", "account.toggleUsername",
"account.resolveBusinessChatLink",
"users.getUsers", "users.getUsers",
"users.getFullUser", "users.getFullUser",
"contacts.getContacts", "contacts.getContacts",

View File

@ -6,7 +6,7 @@ import { isUsernameValid } from './username';
export type DeepLinkMethod = 'resolve' | 'login' | 'passport' | 'settings' | 'join' | 'addstickers' | 'addemoji' | export type DeepLinkMethod = 'resolve' | 'login' | 'passport' | 'settings' | 'join' | 'addstickers' | 'addemoji' |
'setlanguage' | 'addtheme' | 'confirmphone' | 'socks' | 'proxy' | 'privatepost' | 'bg' | 'share' | 'msg' | 'msg_url' | 'setlanguage' | 'addtheme' | 'confirmphone' | 'socks' | 'proxy' | 'privatepost' | 'bg' | 'share' | 'msg' | 'msg_url' |
'invoice' | 'addlist' | 'boost' | 'giftcode'; 'invoice' | 'addlist' | 'boost' | 'giftcode' | 'message';
interface PublicMessageLink { interface PublicMessageLink {
type: 'publicMessageLink'; type: 'publicMessageLink';
@ -59,7 +59,13 @@ interface TelegramPassportLink {
interface PublicUsernameOrBotLink { interface PublicUsernameOrBotLink {
type: 'publicUsernameOrBotLink'; type: 'publicUsernameOrBotLink';
username: string; username: string;
parameter?: string; start?: string;
text?: string;
}
interface BusinessChatLink {
type: 'businessChatLink';
slug: string;
} }
type DeepLink = type DeepLink =
@ -69,7 +75,8 @@ type DeepLink =
PrivateMessageLink | PrivateMessageLink |
ShareLink | ShareLink |
ChatFolderLink | ChatFolderLink |
PublicUsernameOrBotLink; PublicUsernameOrBotLink |
BusinessChatLink;
type BuilderParams<T extends DeepLink> = Record<keyof Omit<T, 'type'>, string | undefined>; type BuilderParams<T extends DeepLink> = Record<keyof Omit<T, 'type'>, string | undefined>;
type BuilderReturnType<T extends DeepLink> = T | undefined; type BuilderReturnType<T extends DeepLink> = T | undefined;
@ -173,8 +180,11 @@ function parseTgLink(url: URL) {
case 'publicUsernameOrBotLink': case 'publicUsernameOrBotLink':
return buildPublicUsernameOrBotLink({ return buildPublicUsernameOrBotLink({
username: queryParams.domain, username: queryParams.domain,
parameter: queryParams.start, start: queryParams.start,
text: queryParams.text,
}); });
case 'businessChatLink':
return buildBusinessChatLink({ slug: queryParams.slug });
default: default:
break; break;
} }
@ -254,8 +264,11 @@ function parseHttpLink(url: URL) {
case 'publicUsernameOrBotLink': case 'publicUsernameOrBotLink':
return buildPublicUsernameOrBotLink({ return buildPublicUsernameOrBotLink({
username: pathParams[0], username: pathParams[0],
parameter: queryParams.start, start: queryParams.start,
text: queryParams.text,
}); });
case 'businessChatLink':
return buildBusinessChatLink({ slug: pathParams[1] });
default: default:
break; break;
} }
@ -285,6 +298,9 @@ function getHttpDeepLinkType(
if (isUsernameValid(pathParams[0]) && isNumber(pathParams[1])) { if (isUsernameValid(pathParams[0]) && isNumber(pathParams[1])) {
return 'publicMessageLink'; return 'publicMessageLink';
} }
if (method === 'm') {
return 'businessChatLink';
}
} else if (len === 3) { } else if (len === 3) {
if (method === 'c' && pathParams.slice(1).every(isNumber)) { if (method === 'c' && pathParams.slice(1).every(isNumber)) {
return 'privateMessageLink'; return 'privateMessageLink';
@ -337,6 +353,8 @@ function getTgDeepLinkType(
return 'loginCodeLink'; return 'loginCodeLink';
case 'passport': case 'passport':
return 'telegramPassportLink'; return 'telegramPassportLink';
case 'message':
return 'businessChatLink';
default: default:
break; break;
} }
@ -467,7 +485,8 @@ function buildPublicUsernameOrBotLink(
): BuilderReturnType<PublicUsernameOrBotLink> { ): BuilderReturnType<PublicUsernameOrBotLink> {
const { const {
username, username,
parameter, start,
text,
} = params; } = params;
if (!username) { if (!username) {
return undefined; return undefined;
@ -478,7 +497,23 @@ function buildPublicUsernameOrBotLink(
return { return {
type: 'publicUsernameOrBotLink', type: 'publicUsernameOrBotLink',
username, username,
parameter, start,
text,
};
}
function buildBusinessChatLink(params: BuilderParams<BusinessChatLink>): BuilderReturnType<BusinessChatLink> {
const {
slug,
} = params;
if (!slug) {
return undefined;
}
return {
type: 'businessChatLink',
slug,
}; };
} }

View File

@ -1,6 +1,6 @@
import { getActions } from '../global'; import { getActions } from '../global';
import type { ApiChatType } from '../api/types'; import type { ApiChatType, ApiFormattedText } from '../api/types';
import type { DeepLinkMethod, PrivateMessageLink } from './deepLinkParser'; import type { DeepLinkMethod, PrivateMessageLink } from './deepLinkParser';
import { API_CHAT_TYPES, RE_TG_LINK } from '../config'; import { API_CHAT_TYPES, RE_TG_LINK } from '../config';
@ -20,7 +20,13 @@ export const processDeepLink = (url: string): boolean => {
case 'publicUsernameOrBotLink': case 'publicUsernameOrBotLink':
actions.openChatByUsername({ actions.openChatByUsername({
username: parsedLink.username, username: parsedLink.username,
startParam: parsedLink.parameter, startParam: parsedLink.start,
text: parsedLink.text,
});
return true;
case 'businessChatLink':
actions.resolveBusinessChatLink({
slug: parsedLink.slug,
}); });
return true; return true;
default: default:
@ -61,7 +67,7 @@ export const processDeepLink = (url: string): boolean => {
case 'resolve': { case 'resolve': {
const { const {
domain, phone, post, comment, voicechat, livestream, start, startattach, attach, thread, topic, domain, phone, post, comment, voicechat, livestream, start, startattach, attach, thread, topic,
appname, startapp, story, appname, startapp, story, text,
} = params; } = params;
const hasStartAttach = params.hasOwnProperty('startattach'); const hasStartAttach = params.hasOwnProperty('startattach');
@ -76,6 +82,7 @@ export const processDeepLink = (url: string): boolean => {
username: domain, username: domain,
startApp: startapp, startApp: startapp,
originalParts: [domain, appname], originalParts: [domain, appname],
text,
}); });
} else if ((hasStartAttach && choose) || (!appname && hasStartApp)) { } else if ((hasStartAttach && choose) || (!appname && hasStartApp)) {
processAttachBotParameters({ processAttachBotParameters({
@ -91,7 +98,12 @@ export const processDeepLink = (url: string): boolean => {
} else if (hasBoost) { } else if (hasBoost) {
processBoostParameters({ usernameOrId: domain }); processBoostParameters({ usernameOrId: domain });
} else if (phone) { } else if (phone) {
openChatByPhoneNumber({ phoneNumber: phone, startAttach: startattach, attach }); openChatByPhoneNumber({
phoneNumber: phone,
startAttach: startattach,
attach,
text,
});
} else if (story) { } else if (story) {
openStoryViewerByUsername({ username: domain, storyId: Number(story) }); openStoryViewerByUsername({ username: domain, storyId: Number(story) });
} else { } else {
@ -180,8 +192,10 @@ export function parseChooseParameter(choose?: string) {
return types.filter((type): type is ApiChatType => API_CHAT_TYPES.includes(type as ApiChatType)); return types.filter((type): type is ApiChatType => API_CHAT_TYPES.includes(type as ApiChatType));
} }
export function formatShareText(url?: string, text?: string, title?: string): string { export function formatShareText(url?: string, text?: string, title?: string): ApiFormattedText {
return [url, title, text].filter(Boolean).join('\n'); return {
text: [url, title, text].filter(Boolean).join('\n'),
};
} }
function handlePrivateMessageLink(link: PrivateMessageLink, actions: ReturnType<typeof getActions>) { function handlePrivateMessageLink(link: PrivateMessageLink, actions: ReturnType<typeof getActions>) {