Layer 143

Invoice links
This commit is contained in:
Eduard Kuzmenko 2022-07-18 19:05:50 +02:00
parent bea1b5f4ac
commit e698dbd99b
11 changed files with 412 additions and 87 deletions

View File

@ -1486,7 +1486,10 @@ export default class ChatBubbles {
return;
}
new PopupPayment(message as Message.message);
new PopupPayment(
message as Message.message,
await this.managers.appPaymentsManager.getInputInvoiceByPeerId(message.peerId, message.mid)
);
return;
}

View File

@ -23,7 +23,7 @@ import { formatPhoneNumber } from "../../helpers/formatPhoneNumber";
import paymentsWrapCurrencyAmount from "../../helpers/paymentsWrapCurrencyAmount";
import ScrollSaver from "../../helpers/scrollSaver";
import tsNow from "../../helpers/tsNow";
import { AccountTmpPassword, InputPaymentCredentials, LabeledPrice, Message, MessageMedia, PaymentRequestedInfo, PaymentSavedCredentials, PaymentsPaymentForm, PaymentsPaymentReceipt, PaymentsValidatedRequestedInfo, PostAddress, ShippingOption } from "../../layer";
import { AccountTmpPassword, InputInvoice, InputPaymentCredentials, LabeledPrice, Message, MessageMedia, PaymentRequestedInfo, PaymentSavedCredentials, PaymentsPaymentForm, PaymentsPaymentReceipt, PaymentsValidatedRequestedInfo, PostAddress, ShippingOption } from "../../layer";
import I18n, { i18n, LangPackKey, _i18n } from "../../lib/langPack";
import { ApiError } from "../../lib/mtproto/apiManager";
import wrapEmojiText from "../../lib/richTextProcessor/wrapEmojiText";
@ -99,10 +99,13 @@ export function PaymentButton(options: {
export type PaymentsCredentialsToken = {type: 'card', token?: string, id?: string};
export default class PopupPayment extends PopupElement {
private currency: string;
private tipButtonsMap: Map<number, HTMLElement>;
constructor(private message: Message.message) {
constructor(
private message: Message.message,
private inputInvoice: InputInvoice,
private paymentForm?: PaymentsPaymentForm | PaymentsPaymentReceipt
) {
super('popup-payment', {
closable: true,
overlayClosable: true,
@ -139,22 +142,31 @@ export default class PopupPayment extends PopupElement {
langPackKey: 'PaymentInfoHint',
langPackArguments: [
paymentsWrapCurrencyAmount(getTotalTotal(), currency),
wrapEmojiText(mediaInvoice.title)
wrapEmojiText(title)
]
});
};
this.listenerSetter.add(rootScope)('payment_sent', ({peerId, mid}) => {
if(this.message.peerId === peerId && this.message.mid === mid) {
onConfirmed();
}
});
let {paymentForm, message} = this;
const {message} = this;
const mediaInvoice = message.media as MessageMedia.messageMediaInvoice;
if(message) {
this.listenerSetter.add(rootScope)('payment_sent', ({peerId, mid}) => {
if(message.peerId === peerId && message.mid === mid) {
onConfirmed();
}
});
}
_i18n(this.title, mediaInvoice.receipt_msg_id ? 'PaymentReceipt' : 'PaymentCheckout');
if(mediaInvoice.pFlags.test) {
const mediaInvoice = message?.media as MessageMedia.messageMediaInvoice;
const isReceipt = mediaInvoice ? !!mediaInvoice.receipt_msg_id : paymentForm._ === 'payments.paymentReceipt';
const isTest = mediaInvoice ? mediaInvoice.pFlags.test : paymentForm.invoice.pFlags.test;
const photo = mediaInvoice ? mediaInvoice.photo : paymentForm.photo;
const title = mediaInvoice ? mediaInvoice.title : paymentForm.title;
const description = mediaInvoice ? mediaInvoice.description : paymentForm.description;
_i18n(this.title, isReceipt ? 'PaymentReceipt' : 'PaymentCheckout');
if(isTest) {
this.title.append(' (Test)');
}
@ -168,11 +180,11 @@ export default class PopupPayment extends PopupElement {
details.classList.add(detailsClassName);
let photoEl: HTMLElement;
if(mediaInvoice.photo) {
if(photo) {
photoEl = document.createElement('div');
photoEl.classList.add(detailsClassName + '-photo', 'media-container-cover');
wrapPhoto({
photo: mediaInvoice.photo,
photo: photo,
container: photoEl,
boxWidth: 100,
boxHeight: 100,
@ -182,27 +194,27 @@ export default class PopupPayment extends PopupElement {
}
const linesClassName = detailsClassName + '-lines';
const lines = document.createElement('div');
lines.classList.add(linesClassName);
const linesEl = document.createElement('div');
linesEl.classList.add(linesClassName);
const title = document.createElement('div');
title.classList.add(linesClassName + '-title');
const titleEl = document.createElement('div');
titleEl.classList.add(linesClassName + '-title');
const description = document.createElement('div');
description.classList.add(linesClassName + '-description');
const descriptionEl = document.createElement('div');
descriptionEl.classList.add(linesClassName + '-description');
const botName = document.createElement('div');
botName.classList.add(linesClassName + '-bot-name');
lines.append(title, description, botName);
linesEl.append(titleEl, descriptionEl, botName);
setInnerHTML(title, wrapEmojiText(mediaInvoice.title));
setInnerHTML(description, wrapEmojiText(mediaInvoice.description));
setInnerHTML(titleEl, wrapEmojiText(title));
setInnerHTML(descriptionEl, wrapEmojiText(description));
const peerTitle = new PeerTitle();
botName.append(peerTitle.element);
details.append(lines);
details.append(linesEl);
itemEl.append(details);
this.scrollable.append(itemEl);
@ -211,16 +223,17 @@ export default class PopupPayment extends PopupElement {
const preloader = putPreloader(preloaderContainer, true);
this.scrollable.container.append(preloaderContainer);
let paymentForm: PaymentsPaymentForm | PaymentsPaymentReceipt;
const isReceipt = !!mediaInvoice.receipt_msg_id;
if(isReceipt) paymentForm = await this.managers.appPaymentsManager.getPaymentReceipt(message.peerId, mediaInvoice.receipt_msg_id);
else paymentForm = await this.managers.appPaymentsManager.getPaymentForm(message.peerId, message.mid);
const inputInvoice = this.inputInvoice;
if(!paymentForm) {
if(isReceipt) paymentForm = await this.managers.appPaymentsManager.getPaymentReceipt(message.peerId, mediaInvoice.receipt_msg_id);
else paymentForm = await this.managers.appPaymentsManager.getPaymentForm(inputInvoice);
this.paymentForm = paymentForm;
}
let savedInfo = (paymentForm as PaymentsPaymentForm).saved_info || (paymentForm as PaymentsPaymentReceipt).info;
const savedCredentials = (paymentForm as PaymentsPaymentForm).saved_credentials;
let [lastRequestedInfo, passwordState, providerPeerTitle] = await Promise.all([
!isReceipt && savedInfo && this.managers.appPaymentsManager.validateRequestedInfo(message.peerId, message.mid, savedInfo),
!isReceipt && savedInfo && this.managers.appPaymentsManager.validateRequestedInfo(inputInvoice, savedInfo),
savedCredentials && this.managers.passwordManager.getState(),
wrapPeerTitle({peerId: paymentForm.provider_id.toPeerId()})
]);
@ -236,7 +249,7 @@ export default class PopupPayment extends PopupElement {
};
const {invoice} = paymentForm;
const currency = this.currency = invoice.currency;
const currency = invoice.currency;
const makeLabel = () => {
const labelEl = document.createElement('div');
@ -326,7 +339,7 @@ export default class PopupPayment extends PopupElement {
};
const tipsLabel = makeLabel();
_i18n(tipsLabel.left, mediaInvoice.receipt_msg_id ? 'PaymentTip' : 'PaymentTipOptional');
_i18n(tipsLabel.left, isReceipt ? 'PaymentTip' : 'PaymentTipOptional');
const input = document.createElement('input');
input.type = 'tel';
// const input: HTMLElement = document.createElement('div');
@ -555,7 +568,7 @@ export default class PopupPayment extends PopupElement {
if(!isReceipt) {
onShippingAddressClick = (focus) => {
new PopupPaymentShipping(paymentForm as PaymentsPaymentForm, message, focus).addEventListener('finish', ({shippingAddress, requestedInfo}) => {
new PopupPaymentShipping(paymentForm as PaymentsPaymentForm, inputInvoice, focus).addEventListener('finish', ({shippingAddress, requestedInfo}) => {
lastRequestedInfo = requestedInfo;
savedInfo = (paymentForm as PaymentsPaymentForm).saved_info = shippingAddress;
setShippingInfo(shippingAddress);
@ -721,8 +734,7 @@ export default class PopupPayment extends PopupElement {
try {
const paymentResult = await this.managers.appPaymentsManager.sendPaymentForm(
message.peerId,
message.mid,
inputInvoice,
(paymentForm as PaymentsPaymentForm).form_id,
lastRequestedInfo?.id,
lastShippingOption?.id,

View File

@ -8,7 +8,7 @@ import PopupElement from ".";
import { attachClickEvent } from "../../helpers/dom/clickEvent";
import placeCaretAtEnd from "../../helpers/dom/placeCaretAtEnd";
import toggleDisability from "../../helpers/dom/toggleDisability";
import { Message, PaymentRequestedInfo, PaymentsPaymentForm, PaymentsValidatedRequestedInfo } from "../../layer";
import { InputInvoice, Message, PaymentRequestedInfo, PaymentsPaymentForm, PaymentsValidatedRequestedInfo } from "../../layer";
import getServerMessageId from "../../lib/appManagers/utils/messageId/getServerMessageId";
import { ApiError } from "../../lib/mtproto/apiManager";
import matchEmail from "../../lib/richTextProcessor/matchEmail";
@ -31,7 +31,7 @@ export default class PopupPaymentShipping extends PopupElement<{
}> {
constructor(
private paymentForm: PaymentsPaymentForm,
private message: Message.message,
private inputInvoice: InputInvoice,
private focus?: ShippingFocusField
) {
super('popup-payment popup-payment-shipping', {
@ -143,7 +143,7 @@ export default class PopupPaymentShipping extends PopupElement<{
};
try {
const requestedInfo = await this.managers.appPaymentsManager.validateRequestedInfo(this.message.peerId, this.message.mid, data, saveCheckboxField?.checked);
const requestedInfo = await this.managers.appPaymentsManager.validateRequestedInfo(this.inputInvoice, data, saveCheckboxField?.checked);
this.dispatchEvent('finish', {
shippingAddress: data,

289
src/layer.d.ts vendored
View File

@ -498,6 +498,8 @@ export namespace User {
apply_min_photo?: true,
fake?: true,
bot_attach_menu?: true,
premium?: true,
attach_menu_enabled?: true,
}>,
id: string | number,
access_hash?: string | number,
@ -964,6 +966,9 @@ export namespace MessageMedia {
export type messageMediaDocument = {
_: 'messageMediaDocument',
flags?: number,
pFlags?: Partial<{
nopremium?: true,
}>,
document?: Document,
ttl_seconds?: number
};
@ -1109,6 +1114,10 @@ export namespace MessageAction {
export type messageActionPaymentSentMe = {
_: 'messageActionPaymentSentMe',
flags?: number,
pFlags?: Partial<{
recurring_init?: true,
recurring_used?: true,
}>,
currency: string,
total_amount: string | number,
payload: Uint8Array,
@ -1119,8 +1128,14 @@ export namespace MessageAction {
export type messageActionPaymentSent = {
_: 'messageActionPaymentSent',
flags?: number,
pFlags?: Partial<{
recurring_init?: true,
recurring_used?: true,
}>,
currency: string,
total_amount: string | number
total_amount: string | number,
invoice_slug?: string
};
export type messageActionPhoneCall = {
@ -1990,7 +2005,7 @@ export namespace MessagesFilter {
/**
* @link https://core.telegram.org/type/Update
*/
export type Update = Update.updateNewMessage | Update.updateMessageID | Update.updateDeleteMessages | Update.updateUserTyping | Update.updateChatUserTyping | Update.updateChatParticipants | Update.updateUserStatus | Update.updateUserName | Update.updateUserPhoto | Update.updateNewEncryptedMessage | Update.updateEncryptedChatTyping | Update.updateEncryption | Update.updateEncryptedMessagesRead | Update.updateChatParticipantAdd | Update.updateChatParticipantDelete | Update.updateDcOptions | Update.updateNotifySettings | Update.updateServiceNotification | Update.updatePrivacy | Update.updateUserPhone | Update.updateReadHistoryInbox | Update.updateReadHistoryOutbox | Update.updateWebPage | Update.updateReadMessagesContents | Update.updateChannelTooLong | Update.updateChannel | Update.updateNewChannelMessage | Update.updateReadChannelInbox | Update.updateDeleteChannelMessages | Update.updateChannelMessageViews | Update.updateChatParticipantAdmin | Update.updateNewStickerSet | Update.updateStickerSetsOrder | Update.updateStickerSets | Update.updateSavedGifs | Update.updateBotInlineQuery | Update.updateBotInlineSend | Update.updateEditChannelMessage | Update.updateBotCallbackQuery | Update.updateEditMessage | Update.updateInlineBotCallbackQuery | Update.updateReadChannelOutbox | Update.updateDraftMessage | Update.updateReadFeaturedStickers | Update.updateRecentStickers | Update.updateConfig | Update.updatePtsChanged | Update.updateChannelWebPage | Update.updateDialogPinned | Update.updatePinnedDialogs | Update.updateBotWebhookJSON | Update.updateBotWebhookJSONQuery | Update.updateBotShippingQuery | Update.updateBotPrecheckoutQuery | Update.updatePhoneCall | Update.updateLangPackTooLong | Update.updateLangPack | Update.updateFavedStickers | Update.updateChannelReadMessagesContents | Update.updateContactsReset | Update.updateChannelAvailableMessages | Update.updateDialogUnreadMark | Update.updateMessagePoll | Update.updateChatDefaultBannedRights | Update.updateFolderPeers | Update.updatePeerSettings | Update.updatePeerLocated | Update.updateNewScheduledMessage | Update.updateDeleteScheduledMessages | Update.updateTheme | Update.updateGeoLiveViewed | Update.updateLoginToken | Update.updateMessagePollVote | Update.updateDialogFilter | Update.updateDialogFilterOrder | Update.updateDialogFilters | Update.updatePhoneCallSignalingData | Update.updateChannelMessageForwards | Update.updateReadChannelDiscussionInbox | Update.updateReadChannelDiscussionOutbox | Update.updatePeerBlocked | Update.updateChannelUserTyping | Update.updatePinnedMessages | Update.updatePinnedChannelMessages | Update.updateChat | Update.updateGroupCallParticipants | Update.updateGroupCall | Update.updatePeerHistoryTTL | Update.updateChatParticipant | Update.updateChannelParticipant | Update.updateBotStopped | Update.updateGroupCallConnection | Update.updateBotCommands | Update.updatePendingJoinRequests | Update.updateBotChatInviteRequester | Update.updateMessageReactions | Update.updateAttachMenuBots | Update.updateWebViewResultSent | Update.updateBotMenuButton | Update.updateSavedRingtones | Update.updateNewDiscussionMessage | Update.updateDeleteDiscussionMessages | Update.updateChannelReload;
export type Update = Update.updateNewMessage | Update.updateMessageID | Update.updateDeleteMessages | Update.updateUserTyping | Update.updateChatUserTyping | Update.updateChatParticipants | Update.updateUserStatus | Update.updateUserName | Update.updateUserPhoto | Update.updateNewEncryptedMessage | Update.updateEncryptedChatTyping | Update.updateEncryption | Update.updateEncryptedMessagesRead | Update.updateChatParticipantAdd | Update.updateChatParticipantDelete | Update.updateDcOptions | Update.updateNotifySettings | Update.updateServiceNotification | Update.updatePrivacy | Update.updateUserPhone | Update.updateReadHistoryInbox | Update.updateReadHistoryOutbox | Update.updateWebPage | Update.updateReadMessagesContents | Update.updateChannelTooLong | Update.updateChannel | Update.updateNewChannelMessage | Update.updateReadChannelInbox | Update.updateDeleteChannelMessages | Update.updateChannelMessageViews | Update.updateChatParticipantAdmin | Update.updateNewStickerSet | Update.updateStickerSetsOrder | Update.updateStickerSets | Update.updateSavedGifs | Update.updateBotInlineQuery | Update.updateBotInlineSend | Update.updateEditChannelMessage | Update.updateBotCallbackQuery | Update.updateEditMessage | Update.updateInlineBotCallbackQuery | Update.updateReadChannelOutbox | Update.updateDraftMessage | Update.updateReadFeaturedStickers | Update.updateRecentStickers | Update.updateConfig | Update.updatePtsChanged | Update.updateChannelWebPage | Update.updateDialogPinned | Update.updatePinnedDialogs | Update.updateBotWebhookJSON | Update.updateBotWebhookJSONQuery | Update.updateBotShippingQuery | Update.updateBotPrecheckoutQuery | Update.updatePhoneCall | Update.updateLangPackTooLong | Update.updateLangPack | Update.updateFavedStickers | Update.updateChannelReadMessagesContents | Update.updateContactsReset | Update.updateChannelAvailableMessages | Update.updateDialogUnreadMark | Update.updateMessagePoll | Update.updateChatDefaultBannedRights | Update.updateFolderPeers | Update.updatePeerSettings | Update.updatePeerLocated | Update.updateNewScheduledMessage | Update.updateDeleteScheduledMessages | Update.updateTheme | Update.updateGeoLiveViewed | Update.updateLoginToken | Update.updateMessagePollVote | Update.updateDialogFilter | Update.updateDialogFilterOrder | Update.updateDialogFilters | Update.updatePhoneCallSignalingData | Update.updateChannelMessageForwards | Update.updateReadChannelDiscussionInbox | Update.updateReadChannelDiscussionOutbox | Update.updatePeerBlocked | Update.updateChannelUserTyping | Update.updatePinnedMessages | Update.updatePinnedChannelMessages | Update.updateChat | Update.updateGroupCallParticipants | Update.updateGroupCall | Update.updatePeerHistoryTTL | Update.updateChatParticipant | Update.updateChannelParticipant | Update.updateBotStopped | Update.updateGroupCallConnection | Update.updateBotCommands | Update.updatePendingJoinRequests | Update.updateBotChatInviteRequester | Update.updateMessageReactions | Update.updateAttachMenuBots | Update.updateWebViewResultSent | Update.updateBotMenuButton | Update.updateSavedRingtones | Update.updateTranscribedAudio | Update.updateNewDiscussionMessage | Update.updateDeleteDiscussionMessages | Update.updateChannelReload;
export namespace Update {
export type updateNewMessage = {
@ -2224,6 +2239,7 @@ export namespace Update {
flags?: number,
pFlags?: Partial<{
masks?: true,
emojis?: true,
}>,
order: Array<string | number>
};
@ -2698,6 +2714,18 @@ export namespace Update {
_: 'updateSavedRingtones'
};
export type updateTranscribedAudio = {
_: 'updateTranscribedAudio',
flags?: number,
pFlags?: Partial<{
pending?: true,
}>,
peer: Peer,
msg_id: number,
transcription_id: string | number,
text: string
};
export type updateNewDiscussionMessage = {
_: 'updateNewDiscussionMessage',
message?: Message
@ -2936,6 +2964,7 @@ export namespace DcOption {
tcpo_only?: true,
cdn?: true,
static?: true,
this_port_only?: true,
}>,
id: number,
ip_address: string,
@ -2961,6 +2990,7 @@ export namespace Config {
revoke_pm_inbox?: true,
blocked_mode?: true,
pfs_enabled?: true,
force_try_ipv6?: true,
}>,
date: number,
expires: number,
@ -3141,7 +3171,7 @@ export namespace EncryptedFile {
_: 'encryptedFile',
id: string | number,
access_hash: string | number,
size: number,
size: string | number,
dc_id: number,
key_fingerprint: number
};
@ -3928,7 +3958,7 @@ export namespace ReceivedNotifyMessage {
/**
* @link https://core.telegram.org/type/ExportedChatInvite
*/
export type ExportedChatInvite = ExportedChatInvite.chatInviteExported;
export type ExportedChatInvite = ExportedChatInvite.chatInviteExported | ExportedChatInvite.chatInvitePublicJoinRequests;
export namespace ExportedChatInvite {
export type chatInviteExported = {
@ -3949,6 +3979,10 @@ export namespace ExportedChatInvite {
requested?: number,
title?: string
};
export type chatInvitePublicJoinRequests = {
_: 'chatInvitePublicJoinRequests'
};
}
/**
@ -4036,6 +4070,7 @@ export namespace StickerSet {
masks?: true,
animated?: true,
videos?: true,
emojis?: true,
}>,
installed_date?: number,
id: string | number,
@ -4090,10 +4125,13 @@ export type BotInfo = BotInfo.botInfo;
export namespace BotInfo {
export type botInfo = {
_: 'botInfo',
user_id: string | number,
description: string,
commands: Array<BotCommand>,
menu_button: BotMenuButton
flags?: number,
user_id?: string | number,
description?: string,
description_photo?: Photo,
description_document?: Document,
commands?: Array<BotCommand>,
menu_button?: BotMenuButton
};
}
@ -5273,6 +5311,10 @@ export namespace MessagesFeaturedStickers {
export type messagesFeaturedStickers = {
_: 'messages.featuredStickers',
flags?: number,
pFlags?: Partial<{
premium?: true,
}>,
hash: string | number,
count: number,
sets: Array<StickerSetCovered>,
@ -5802,11 +5844,13 @@ export namespace Invoice {
flexible?: true,
phone_to_provider?: true,
email_to_provider?: true,
recurring?: true,
}>,
currency: string,
prices: Array<LabeledPrice>,
max_tip_amount?: string | number,
suggested_tip_amounts?: Array<string | number>
suggested_tip_amounts?: Array<string | number>,
recurring_terms_url?: string
};
}
@ -5966,6 +6010,9 @@ export namespace PaymentsPaymentForm {
}>,
form_id: string | number,
bot_id: string | number,
title: string,
description: string,
photo?: WebDocument,
invoice: Invoice,
provider_id: string | number,
url: string,
@ -6234,6 +6281,10 @@ export type PhoneConnection = PhoneConnection.phoneConnection | PhoneConnection.
export namespace PhoneConnection {
export type phoneConnection = {
_: 'phoneConnection',
flags?: number,
pFlags?: Partial<{
tcp?: true,
}>,
id: string | number,
ip: string,
ipv6: string,
@ -6881,7 +6932,7 @@ export type FileHash = FileHash.fileHash;
export namespace FileHash {
export type fileHash = {
_: 'fileHash',
offset: number,
offset: string | number,
limit: number,
hash: Uint8Array
};
@ -6954,7 +7005,7 @@ export namespace SecureFile {
_: 'secureFile',
id: string | number,
access_hash: string | number,
size: number,
size: string | number,
dc_id: number,
date: number,
file_hash: Uint8Array,
@ -8333,7 +8384,7 @@ export namespace PaymentsBankCardData {
/**
* @link https://core.telegram.org/type/DialogFilter
*/
export type DialogFilter = DialogFilter.dialogFilter;
export type DialogFilter = DialogFilter.dialogFilter | DialogFilter.dialogFilterDefault;
export namespace DialogFilter {
export type dialogFilter = {
@ -8359,6 +8410,10 @@ export namespace DialogFilter {
peerId?: PeerId,
folder_id?: number
};
export type dialogFilterDefault = {
_: 'dialogFilterDefault'
};
}
/**
@ -9199,6 +9254,9 @@ export namespace SponsoredMessage {
export type sponsoredMessage = {
_: 'sponsoredMessage',
flags?: number,
pFlags?: Partial<{
recommended?: true,
}>,
random_id: Uint8Array,
from_id?: Peer,
chat_invite?: ChatInvite,
@ -9407,6 +9465,7 @@ export namespace AvailableReaction {
flags?: number,
pFlags?: Partial<{
inactive?: true,
premium?: true,
}>,
reaction: string,
title: string,
@ -9549,9 +9608,11 @@ export namespace AttachMenuBot {
flags?: number,
pFlags?: Partial<{
inactive?: true,
has_settings?: true,
}>,
bot_id: string | number,
short_name: string,
peer_types: Array<AttachMenuPeerType>,
icons: Array<AttachMenuBotIcon>
};
}
@ -9705,6 +9766,98 @@ export namespace AccountSavedRingtone {
};
}
/**
* @link https://core.telegram.org/type/AttachMenuPeerType
*/
export type AttachMenuPeerType = AttachMenuPeerType.attachMenuPeerTypeSameBotPM | AttachMenuPeerType.attachMenuPeerTypeBotPM | AttachMenuPeerType.attachMenuPeerTypePM | AttachMenuPeerType.attachMenuPeerTypeChat | AttachMenuPeerType.attachMenuPeerTypeBroadcast;
export namespace AttachMenuPeerType {
export type attachMenuPeerTypeSameBotPM = {
_: 'attachMenuPeerTypeSameBotPM'
};
export type attachMenuPeerTypeBotPM = {
_: 'attachMenuPeerTypeBotPM'
};
export type attachMenuPeerTypePM = {
_: 'attachMenuPeerTypePM'
};
export type attachMenuPeerTypeChat = {
_: 'attachMenuPeerTypeChat'
};
export type attachMenuPeerTypeBroadcast = {
_: 'attachMenuPeerTypeBroadcast'
};
}
/**
* @link https://core.telegram.org/type/InputInvoice
*/
export type InputInvoice = InputInvoice.inputInvoiceMessage | InputInvoice.inputInvoiceSlug;
export namespace InputInvoice {
export type inputInvoiceMessage = {
_: 'inputInvoiceMessage',
peer: InputPeer,
msg_id: number
};
export type inputInvoiceSlug = {
_: 'inputInvoiceSlug',
slug: string
};
}
/**
* @link https://core.telegram.org/type/payments.ExportedInvoice
*/
export type PaymentsExportedInvoice = PaymentsExportedInvoice.paymentsExportedInvoice;
export namespace PaymentsExportedInvoice {
export type paymentsExportedInvoice = {
_: 'payments.exportedInvoice',
url: string
};
}
/**
* @link https://core.telegram.org/type/messages.TranscribedAudio
*/
export type MessagesTranscribedAudio = MessagesTranscribedAudio.messagesTranscribedAudio;
export namespace MessagesTranscribedAudio {
export type messagesTranscribedAudio = {
_: 'messages.transcribedAudio',
flags?: number,
pFlags?: Partial<{
pending?: true,
}>,
transcription_id: string | number,
text: string
};
}
/**
* @link https://core.telegram.org/type/help.PremiumPromo
*/
export type HelpPremiumPromo = HelpPremiumPromo.helpPremiumPromo;
export namespace HelpPremiumPromo {
export type helpPremiumPromo = {
_: 'help.premiumPromo',
status_text: string,
status_entities: Array<MessageEntity>,
video_sections: Array<string>,
videos: Array<Document>,
currency: string,
monthly_amount: string | number,
users: Array<User>
};
}
export interface ConstructorDeclMap {
'error': Error.error,
'inputPeerEmpty': InputPeer.inputPeerEmpty,
@ -10688,6 +10841,19 @@ export interface ConstructorDeclMap {
'notificationSoundRingtone': NotificationSound.notificationSoundRingtone,
'account.savedRingtone': AccountSavedRingtone.accountSavedRingtone,
'account.savedRingtoneConverted': AccountSavedRingtone.accountSavedRingtoneConverted,
'attachMenuPeerTypeSameBotPM': AttachMenuPeerType.attachMenuPeerTypeSameBotPM,
'attachMenuPeerTypeBotPM': AttachMenuPeerType.attachMenuPeerTypeBotPM,
'attachMenuPeerTypePM': AttachMenuPeerType.attachMenuPeerTypePM,
'attachMenuPeerTypeChat': AttachMenuPeerType.attachMenuPeerTypeChat,
'attachMenuPeerTypeBroadcast': AttachMenuPeerType.attachMenuPeerTypeBroadcast,
'chatInvitePublicJoinRequests': ExportedChatInvite.chatInvitePublicJoinRequests,
'inputInvoiceMessage': InputInvoice.inputInvoiceMessage,
'inputInvoiceSlug': InputInvoice.inputInvoiceSlug,
'payments.exportedInvoice': PaymentsExportedInvoice.paymentsExportedInvoice,
'updateTranscribedAudio': Update.updateTranscribedAudio,
'messages.transcribedAudio': MessagesTranscribedAudio.messagesTranscribedAudio,
'dialogFilterDefault': DialogFilter.dialogFilterDefault,
'help.premiumPromo': HelpPremiumPromo.helpPremiumPromo,
'messageEntityEmoji': MessageEntity.messageEntityEmoji,
'messageEntityHighlight': MessageEntity.messageEntityHighlight,
'messageEntityLinebreak': MessageEntity.messageEntityLinebreak,
@ -11073,7 +11239,7 @@ export type UploadGetFile = {
precise?: boolean,
cdn_supported?: boolean,
location: InputFileLocation,
offset: number,
offset: string | number,
limit: number
};
@ -11216,7 +11382,9 @@ export type AccountSetPrivacy = {
};
export type AccountDeleteAccount = {
reason: string
flags?: number,
reason: string,
password?: InputCheckPasswordSRP
};
export type AccountGetAccountTTL = {
@ -11493,12 +11661,13 @@ export type MessagesSearchGlobal = {
export type MessagesReorderStickerSets = {
flags?: number,
masks?: boolean,
emojis?: boolean,
order: Array<string | number>
};
export type MessagesGetDocumentByHash = {
sha256: Uint8Array,
size: number,
size: string | number,
mime_type: string
};
@ -11680,6 +11849,7 @@ export type MessagesClearRecentStickers = {
export type MessagesGetArchivedStickers = {
flags?: number,
masks?: boolean,
emojis?: boolean,
offset_id: string | number,
limit: number
};
@ -11797,8 +11967,7 @@ export type UploadGetWebFile = {
export type PaymentsGetPaymentForm = {
flags?: number,
peer: InputPeer,
msg_id: number,
invoice: InputInvoice,
theme_params?: DataJSON
};
@ -11810,16 +11979,14 @@ export type PaymentsGetPaymentReceipt = {
export type PaymentsValidateRequestedInfo = {
flags?: number,
save?: boolean,
peer: InputPeer,
msg_id: number,
invoice: InputInvoice,
info: PaymentRequestedInfo
};
export type PaymentsSendPaymentForm = {
flags?: number,
form_id: string | number,
peer: InputPeer,
msg_id: number,
invoice: InputInvoice,
requested_info_id?: string,
shipping_option_id?: string,
credentials: InputPaymentCredentials,
@ -11941,7 +12108,7 @@ export type PhoneSaveCallDebug = {
export type UploadGetCdnFile = {
file_token: Uint8Array,
offset: number,
offset: string | number,
limit: number
};
@ -11994,7 +12161,7 @@ export type ChannelsGetAdminLog = {
export type UploadGetCdnFileHashes = {
file_token: Uint8Array,
offset: number
offset: string | number
};
export type MessagesSendScreenshotNotification = {
@ -12100,7 +12267,7 @@ export type MessagesSearchStickerSets = {
export type UploadGetFileHashes = {
location: InputFileLocation,
offset: number
offset: string | number
};
export type HelpGetTermsOfServiceUpdate = {
@ -12187,7 +12354,7 @@ export type AccountInitTakeoutSession = {
message_megagroups?: boolean,
message_channels?: boolean,
files?: boolean,
file_max_size?: number
file_max_size?: string | number
};
export type AccountFinishTakeoutSession = {
@ -13136,7 +13303,8 @@ export type MessagesRequestWebView = {
url?: string,
start_param?: string,
theme_params?: DataJSON,
reply_to_msg_id?: number
reply_to_msg_id?: number,
send_as?: InputPeer
};
export type MessagesProlongWebView = {
@ -13145,7 +13313,8 @@ export type MessagesProlongWebView = {
peer: InputPeer,
bot: InputUser,
query_id: string | number,
reply_to_msg_id?: number
reply_to_msg_id?: number,
send_as?: InputPeer
};
export type MessagesRequestSimpleWebView = {
@ -13199,6 +13368,61 @@ export type BotsSetBotGroupDefaultAdminRights = {
admin_rights: ChatAdminRights
};
export type PhoneSaveCallLog = {
peer: InputPhoneCall,
file: InputFile
};
export type ChannelsToggleJoinToSend = {
channel: InputChannel,
enabled: boolean
};
export type ChannelsToggleJoinRequest = {
channel: InputChannel,
enabled: boolean
};
export type PaymentsExportInvoice = {
invoice_media: InputMedia
};
export type MessagesTranscribeAudio = {
peer: InputPeer,
msg_id: number
};
export type MessagesRateTranscribedAudio = {
peer: InputPeer,
msg_id: number,
transcription_id: string | number,
good: boolean
};
export type PaymentsAssignAppStoreTransaction = {
flags?: number,
restore?: boolean,
receipt: Uint8Array
};
export type PaymentsAssignPlayMarketTransaction = {
purchase_token: string
};
export type PaymentsCanPurchasePremium = {
};
export type HelpGetPremiumPromo = {
};
export type PaymentsRequestRecurringPayment = {
user_id: InputUser,
recurring_init_charge: string,
invoice_media: InputMedia
};
export interface MethodDeclMap {
'invokeAfterMsg': {req: InvokeAfterMsg, res: any},
'invokeAfterMsgs': {req: InvokeAfterMsgs, res: any},
@ -13634,5 +13858,16 @@ export interface MethodDeclMap {
'account.uploadRingtone': {req: AccountUploadRingtone, res: Document},
'bots.setBotBroadcastDefaultAdminRights': {req: BotsSetBotBroadcastDefaultAdminRights, res: boolean},
'bots.setBotGroupDefaultAdminRights': {req: BotsSetBotGroupDefaultAdminRights, res: boolean},
'phone.saveCallLog': {req: PhoneSaveCallLog, res: boolean},
'channels.toggleJoinToSend': {req: ChannelsToggleJoinToSend, res: Updates},
'channels.toggleJoinRequest': {req: ChannelsToggleJoinRequest, res: Updates},
'payments.exportInvoice': {req: PaymentsExportInvoice, res: PaymentsExportedInvoice},
'messages.transcribeAudio': {req: MessagesTranscribeAudio, res: MessagesTranscribedAudio},
'messages.rateTranscribedAudio': {req: MessagesRateTranscribedAudio, res: boolean},
'payments.assignAppStoreTransaction': {req: PaymentsAssignAppStoreTransaction, res: Updates},
'payments.assignPlayMarketTransaction': {req: PaymentsAssignPlayMarketTransaction, res: Updates},
'payments.canPurchasePremium': {req: PaymentsCanPurchasePremium, res: boolean},
'help.getPremiumPromo': {req: HelpGetPremiumPromo, res: HelpPremiumPromo},
'payments.requestRecurringPayment': {req: PaymentsRequestRecurringPayment, res: Updates},
}

View File

@ -24,7 +24,7 @@ import { MOUNT_CLASS_TO } from '../../config/debug';
import appNavigationController from '../../components/appNavigationController';
import AppPrivateSearchTab from '../../components/sidebarRight/tabs/search';
import I18n, { i18n, join, LangPackKey } from '../langPack';
import { ChatFull, ChatInvite, ChatParticipant, ChatParticipants, SendMessageAction } from '../../layer';
import { ChatFull, ChatInvite, ChatParticipant, ChatParticipants, Message, SendMessageAction } from '../../layer';
import { hslaStringToHex } from '../../helpers/color';
import PeerTitle from '../../components/peerTitle';
import PopupPeer from '../../components/popups/peer';
@ -89,6 +89,7 @@ import getFilesFromEvent from '../../helpers/files/getFilesFromEvent';
import apiManagerProxy from '../mtproto/mtprotoworker';
import wrapPeerTitle from '../../components/wrappers/peerTitle';
import appRuntimeManager from './appRuntimeManager';
import PopupPayment from '../../components/popups/payment';
export const CHAT_ANIMATION_GROUP = 'chat';
@ -486,6 +487,20 @@ export class AppImManager extends EventListenerBase<{
}
});
// * t.me/invoice/asdasdad
// * t.me/$asdasdad
this.addAnchorListener<{pathnameParams: ['invoice', string] | string}>({
name: 'invoice',
callback: ({pathnameParams}) => {
const link: InternalLink = {
_: INTERNAL_LINK_TYPE.INVOICE,
slug: pathnameParams.length > 1 ? pathnameParams[1] : pathnameParams[0].slice(1)
};
this.processInternalLink(link);
}
});
// Support old t.me/joinchat/asd and new t.me/+asd
this.addAnchorListener<{pathnameParams: ['joinchat', string]}>({
name: 'joinchat',
@ -619,6 +634,19 @@ export class AppImManager extends EventListenerBase<{
}
});
this.addAnchorListener<{
uriParams: {
slug: string
}
}>({
name: 'invoice',
protocol: 'tg',
callback: ({uriParams}) => {
const link = this.makeLink(INTERNAL_LINK_TYPE.INVOICE, uriParams);
this.processInternalLink(link);
}
});
['joinchat' as const, 'join' as const].forEach((name) => {
this.addAnchorListener<{
uriParams: {
@ -841,6 +869,29 @@ export class AppImManager extends EventListenerBase<{
break;
}
case INTERNAL_LINK_TYPE.INVOICE: {
this.managers.appPaymentsManager.getInputInvoiceBySlug(link.slug).then((inputInvoice) => {
this.managers.appPaymentsManager.getPaymentForm(inputInvoice).then((paymentForm) => {
// const message: Message.message = {
// _: 'message',
// date: 0,
// id: 0,
// peerId: 0,
// peer_id: undefined,
// message: '',
// media: {
// _: 'messageMediaInvoice',
// currency: paymentForm.invoice.currency,
// description: paymentForm.description,
// }
// };
new PopupPayment(undefined, inputInvoice, paymentForm);
});
});
break;
}
default: {
this.log.warn('Not supported internal link:', link);
break;
@ -858,7 +909,7 @@ export class AppImManager extends EventListenerBase<{
private addAnchorListener<Params extends {pathnameParams?: any, uriParams?: any}>(options: {
name: 'showMaskedAlert' | 'execBotCommand' | 'searchByHashtag' | 'addstickers' | 'im' |
'resolve' | 'privatepost' | 'addstickers' | 'voicechat' | 'joinchat' | 'join',
'resolve' | 'privatepost' | 'addstickers' | 'voicechat' | 'joinchat' | 'join' | 'invoice',
protocol?: 'tg',
callback: (params: Params, element?: HTMLAnchorElement) => boolean | any,
noPathnameParams?: boolean,

View File

@ -4,15 +4,29 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { InputPaymentCredentials, PaymentRequestedInfo, PaymentsPaymentForm } from "../../layer";
import { InputInvoice, InputPaymentCredentials, PaymentRequestedInfo, PaymentsPaymentForm } from "../../layer";
import { AppManager } from "./manager";
import getServerMessageId from "./utils/messageId/getServerMessageId";
export default class AppPaymentsManager extends AppManager {
public getPaymentForm(peerId: PeerId, mid: number) {
return this.apiManager.invokeApi('payments.getPaymentForm', {
public getInputInvoiceBySlug(slug: string): InputInvoice.inputInvoiceSlug {
return {
_: 'inputInvoiceSlug',
slug
};
}
public getInputInvoiceByPeerId(peerId: PeerId, mid: number): InputInvoice.inputInvoiceMessage {
return {
_: 'inputInvoiceMessage',
peer: this.appPeersManager.getInputPeerById(peerId),
msg_id: getServerMessageId(mid)
};
}
public getPaymentForm(invoice: InputInvoice) {
return this.apiManager.invokeApi('payments.getPaymentForm', {
invoice
}).then((paymentForm) => {
this.appUsersManager.saveApiUsers(paymentForm.users);
@ -31,18 +45,16 @@ export default class AppPaymentsManager extends AppManager {
});
}
public validateRequestedInfo(peerId: PeerId, mid: number, info: PaymentRequestedInfo, save?: boolean) {
public validateRequestedInfo(invoice: InputInvoice, info: PaymentRequestedInfo, save?: boolean) {
return this.apiManager.invokeApi('payments.validateRequestedInfo', {
save,
peer: this.appPeersManager.getInputPeerById(peerId),
msg_id: getServerMessageId(mid),
invoice,
info
});
}
public sendPaymentForm(
peerId: PeerId,
mid: number,
invoice: InputInvoice,
formId: PaymentsPaymentForm['form_id'],
requestedInfoId: string,
shippingOptionId: string,
@ -51,8 +63,7 @@ export default class AppPaymentsManager extends AppManager {
) {
return this.apiManager.invokeApi('payments.sendPaymentForm', {
form_id: formId,
peer: this.appPeersManager.getInputPeerById(peerId),
msg_id: getServerMessageId(mid),
invoice,
requested_info_id: requestedInfoId,
shipping_option_id: shippingOptionId,
credentials,

View File

@ -10,10 +10,11 @@ export enum INTERNAL_LINK_TYPE {
STICKER_SET,
JOIN_CHAT,
VOICE_CHAT,
USER_PHONE_NUMBER
USER_PHONE_NUMBER,
INVOICE
};
export type InternalLink = InternalLink.InternalLinkMessage | InternalLink.InternalLinkPrivatePost | InternalLink.InternalLinkStickerSet | InternalLink.InternalLinkJoinChat | InternalLink.InternalLinkVoiceChat | InternalLink.InternalLinkUserPhoneNumber;
export type InternalLink = InternalLink.InternalLinkMessage | InternalLink.InternalLinkPrivatePost | InternalLink.InternalLinkStickerSet | InternalLink.InternalLinkJoinChat | InternalLink.InternalLinkVoiceChat | InternalLink.InternalLinkUserPhoneNumber | InternalLink.InternalLinkInvoice;
export namespace InternalLink {
export interface InternalLinkMessage {
@ -56,6 +57,11 @@ export namespace InternalLink {
_: INTERNAL_LINK_TYPE.USER_PHONE_NUMBER,
phone: string
}
export interface InternalLinkInvoice {
_: INTERNAL_LINK_TYPE.INVOICE,
slug: string
}
}
export type InternalLinkTypeMap = {
@ -64,5 +70,6 @@ export type InternalLinkTypeMap = {
[INTERNAL_LINK_TYPE.STICKER_SET]: InternalLink.InternalLinkStickerSet,
[INTERNAL_LINK_TYPE.JOIN_CHAT]: InternalLink.InternalLinkJoinChat,
[INTERNAL_LINK_TYPE.VOICE_CHAT]: InternalLink.InternalLinkVoiceChat,
[INTERNAL_LINK_TYPE.USER_PHONE_NUMBER]: InternalLink.InternalLinkUserPhoneNumber
[INTERNAL_LINK_TYPE.USER_PHONE_NUMBER]: InternalLink.InternalLinkUserPhoneNumber,
[INTERNAL_LINK_TYPE.INVOICE]: InternalLink.InternalLinkInvoice
};

File diff suppressed because one or more lines are too long

View File

@ -18,6 +18,12 @@ export default function wrapUrl(url: string, unsafe?: number | boolean): {url: s
url = 'tg://unsafe_url?url=' + encodeURIComponent(url);
} else */if((tgMeMatch = url.match(/^(?:https?:\/\/)?t(?:elegram)?\.me\/(.+)/))) {
const fullPath = tgMeMatch[1];
const path = fullPath.split('/');
if(path[0] && path[0][0] === '$' && path[0].length > 1) {
onclick = 'invoice';
return {url, onclick};
}
// second regexp is for phone numbers (t.me/+38050...)
if(/^\W/.test(fullPath) && !PHONE_NUMBER_REG_EXP.test(fullPath)) {
@ -25,11 +31,11 @@ export default function wrapUrl(url: string, unsafe?: number | boolean): {url: s
return {url, onclick};
}
const path = fullPath.split('/');
switch(path[0]) {
case 'joinchat':
case 'addstickers':
case 'voicechat':
case 'invoice':
onclick = path[0];
break;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long