Recurring payments
This commit is contained in:
parent
30fd544802
commit
24bdb104b0
@ -27,9 +27,11 @@ import { AccountTmpPassword, InputInvoice, InputPaymentCredentials, LabeledPrice
|
|||||||
import I18n, { i18n, LangPackKey, _i18n } from "../../lib/langPack";
|
import I18n, { i18n, LangPackKey, _i18n } from "../../lib/langPack";
|
||||||
import { ApiError } from "../../lib/mtproto/apiManager";
|
import { ApiError } from "../../lib/mtproto/apiManager";
|
||||||
import wrapEmojiText from "../../lib/richTextProcessor/wrapEmojiText";
|
import wrapEmojiText from "../../lib/richTextProcessor/wrapEmojiText";
|
||||||
|
import wrapRichText from "../../lib/richTextProcessor/wrapRichText";
|
||||||
import rootScope from "../../lib/rootScope";
|
import rootScope from "../../lib/rootScope";
|
||||||
import AvatarElement from "../avatar";
|
import AvatarElement from "../avatar";
|
||||||
import Button from "../button";
|
import Button from "../button";
|
||||||
|
import CheckboxField from "../checkboxField";
|
||||||
import PeerTitle from "../peerTitle";
|
import PeerTitle from "../peerTitle";
|
||||||
import { putPreloader } from "../putPreloader";
|
import { putPreloader } from "../putPreloader";
|
||||||
import Row from "../row";
|
import Row from "../row";
|
||||||
@ -240,10 +242,6 @@ export default class PopupPayment extends PopupElement {
|
|||||||
|
|
||||||
// console.log(paymentForm, lastRequestedInfo);
|
// console.log(paymentForm, lastRequestedInfo);
|
||||||
|
|
||||||
await peerTitle.update({peerId: paymentForm.bot_id.toPeerId()});
|
|
||||||
preloaderContainer.remove();
|
|
||||||
this.element.classList.remove('is-loading');
|
|
||||||
|
|
||||||
const wrapAmount = (amount: string | number, skipSymbol?: boolean) => {
|
const wrapAmount = (amount: string | number, skipSymbol?: boolean) => {
|
||||||
return paymentsWrapCurrencyAmount(amount, currency, skipSymbol);
|
return paymentsWrapCurrencyAmount(amount, currency, skipSymbol);
|
||||||
};
|
};
|
||||||
@ -251,6 +249,13 @@ export default class PopupPayment extends PopupElement {
|
|||||||
const {invoice} = paymentForm;
|
const {invoice} = paymentForm;
|
||||||
const currency = invoice.currency;
|
const currency = invoice.currency;
|
||||||
|
|
||||||
|
const isRecurring = invoice.pFlags.recurring && !isReceipt;
|
||||||
|
|
||||||
|
await peerTitle.update({peerId: paymentForm.bot_id.toPeerId()});
|
||||||
|
const peerTitle2 = isRecurring ? await wrapPeerTitle({peerId: paymentForm.bot_id.toPeerId()}) : undefined;
|
||||||
|
preloaderContainer.remove();
|
||||||
|
this.element.classList.remove('is-loading');
|
||||||
|
|
||||||
const makeLabel = () => {
|
const makeLabel = () => {
|
||||||
const labelEl = document.createElement('div');
|
const labelEl = document.createElement('div');
|
||||||
labelEl.classList.add(pricesClassName + '-price');
|
labelEl.classList.add(pricesClassName + '-price');
|
||||||
@ -669,9 +674,23 @@ export default class PopupPayment extends PopupElement {
|
|||||||
shippingEmailRow,
|
shippingEmailRow,
|
||||||
shippingPhoneRow,
|
shippingPhoneRow,
|
||||||
].filter(Boolean);
|
].filter(Boolean);
|
||||||
|
|
||||||
|
const acceptTermsCheckboxField = isRecurring && new CheckboxField({
|
||||||
|
text: 'Payments.Recurrent.Accept',
|
||||||
|
textArgs: [wrapRichText(invoice.recurring_terms_url), peerTitle2]
|
||||||
|
});
|
||||||
|
|
||||||
|
const acceptTermsRow = isRecurring && createRow({
|
||||||
|
checkboxField: acceptTermsCheckboxField,
|
||||||
|
noCheckboxSubtitle: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const recurringElements = isRecurring ? [document.createElement('hr'), acceptTermsRow.container] : [];
|
||||||
|
|
||||||
this.scrollable.append(...[
|
this.scrollable.append(...[
|
||||||
document.createElement('hr'),
|
document.createElement('hr'),
|
||||||
...rows.map((row) => row.container)
|
...rows.map((row) => row.container),
|
||||||
|
...recurringElements
|
||||||
].filter(Boolean));
|
].filter(Boolean));
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -779,7 +798,11 @@ export default class PopupPayment extends PopupElement {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
let payButton: HTMLElement;
|
const onChange = () => {
|
||||||
|
payButton.disabled = !!(acceptTermsCheckboxField && !acceptTermsCheckboxField.checked);
|
||||||
|
};
|
||||||
|
|
||||||
|
let payButton: HTMLButtonElement;
|
||||||
if(isReceipt) {
|
if(isReceipt) {
|
||||||
payButton = PaymentButton({
|
payButton = PaymentButton({
|
||||||
onClick: () => this.hide(),
|
onClick: () => this.hide(),
|
||||||
@ -792,6 +815,11 @@ export default class PopupPayment extends PopupElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onChange();
|
||||||
|
if(acceptTermsCheckboxField) {
|
||||||
|
acceptTermsCheckboxField.input.addEventListener('change', onChange);
|
||||||
|
}
|
||||||
|
|
||||||
this.body.append(this.btnConfirmOnEnter = payButton);
|
this.body.append(this.btnConfirmOnEnter = payButton);
|
||||||
|
|
||||||
this.onContentUpdate();
|
this.onContentUpdate();
|
||||||
|
@ -250,7 +250,9 @@ export default async function wrapMessageActionTextNewUnsafe(message: MyMessage,
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 'messageActionPaymentSent': {
|
case 'messageActionPaymentSent': {
|
||||||
langPackKey = 'PaymentSuccessfullyPaidNoItem';
|
const isRecurringInit = action.pFlags.recurring_init;
|
||||||
|
const isRecurringUsed = action.pFlags.recurring_used;
|
||||||
|
langPackKey = isRecurringUsed ? 'Chat.Service.PaymentSentRecurringUsedNoTitle' : (isRecurringInit ? 'Chat.Service.PaymentSentRecurringInitNoTitle' : 'Chat.Service.PaymentSent1NoTitle');
|
||||||
const price = paymentsWrapCurrencyAmount(action.total_amount, action.currency);
|
const price = paymentsWrapCurrencyAmount(action.total_amount, action.currency);
|
||||||
args = [price, getNameDivHTML(message.peerId, plain)];
|
args = [price, getNameDivHTML(message.peerId, plain)];
|
||||||
|
|
||||||
@ -263,7 +265,7 @@ export default async function wrapMessageActionTextNewUnsafe(message: MyMessage,
|
|||||||
if(!invoiceMessage) {
|
if(!invoiceMessage) {
|
||||||
managers.appMessagesManager.fetchMessageReplyTo(message);
|
managers.appMessagesManager.fetchMessageReplyTo(message);
|
||||||
} else {
|
} else {
|
||||||
langPackKey = 'PaymentSuccessfullyPaid';
|
langPackKey = isRecurringUsed ? 'Chat.Service.PaymentSentRecurringUsed' : (isRecurringInit ? 'Chat.Service.PaymentSentRecurringInit' : 'Chat.Service.PaymentSent1');
|
||||||
args.push(wrapLinkToMessage(invoiceMessage, plain));
|
args.push(wrapLinkToMessage(invoiceMessage, plain));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
src/lang.ts
11
src/lang.ts
@ -703,10 +703,6 @@ const lang = {
|
|||||||
"PaymentInvoice": "INVOICE",
|
"PaymentInvoice": "INVOICE",
|
||||||
"PaymentTestInvoice": "TEST INVOICE",
|
"PaymentTestInvoice": "TEST INVOICE",
|
||||||
"PaymentReceipt": "Receipt",
|
"PaymentReceipt": "Receipt",
|
||||||
"PaymentSuccessfullyPaid": "You successfully transferred %1$s to %2$s for %3$s",
|
|
||||||
"PaymentSuccessfullyPaidNoItem": "You successfully transferred %1$s to %2$s",
|
|
||||||
// "PaymentSuccessfullyPaidRecurrent": "You successfully transferred %1$s to %2$s for %3$s and allowed future recurring payments",
|
|
||||||
// "PaymentSuccessfullyPaidNoItemRecurrent": "You successfully transferred %1$s to %2$s and allowed future recurring payments",
|
|
||||||
"PaymentCheckout": "Checkout",
|
"PaymentCheckout": "Checkout",
|
||||||
"PaymentTransactionTotal": "Total",
|
"PaymentTransactionTotal": "Total",
|
||||||
"PaymentTip": "Tip",
|
"PaymentTip": "Tip",
|
||||||
@ -835,6 +831,12 @@ const lang = {
|
|||||||
"Chat.Service.Channel.UpdatedVideo": "Channel video updated",
|
"Chat.Service.Channel.UpdatedVideo": "Channel video updated",
|
||||||
"Chat.Service.BotPermissionAllowed": "You allowed this bot to message you when you logged in on %@",
|
"Chat.Service.BotPermissionAllowed": "You allowed this bot to message you when you logged in on %@",
|
||||||
"Chat.Service.Group.UpdatedPinnedMessage": "%@ pinned \"%@\"",
|
"Chat.Service.Group.UpdatedPinnedMessage": "%@ pinned \"%@\"",
|
||||||
|
"Chat.Service.PaymentSent1": "You have successfully transferred **%1$@** to **%2$@** for **%3$@**",
|
||||||
|
"Chat.Service.PaymentSent1NoTitle": "You have successfully transferred **%1$@** to **%2$@**",
|
||||||
|
"Chat.Service.PaymentSentRecurringInit": "You successfully transferred **%1$@** to **%2$@** for **%3$@** and allowed future recurring payments",
|
||||||
|
"Chat.Service.PaymentSentRecurringInitNoTitle": "You successfully transferred **%1$@** to **%2$@** and allowed future recurring payments",
|
||||||
|
"Chat.Service.PaymentSentRecurringUsed": "You have just successfully transferred **%1$@** to **%2$@** for **%3$@** via recurrent payments",
|
||||||
|
"Chat.Service.PaymentSentRecurringUsedNoTitle": "You have just successfully transferred **%1$@** to **%2$@** via recurrent payments",
|
||||||
"Chat.Service.VoiceChatStarted": "%1$@ started a [video chat](open)",
|
"Chat.Service.VoiceChatStarted": "%1$@ started a [video chat](open)",
|
||||||
"Chat.Service.VoiceChatStartedYou": "You started a [video chat](open)",
|
"Chat.Service.VoiceChatStartedYou": "You started a [video chat](open)",
|
||||||
"Chat.Service.VoiceChatStarted.Channel": "[Live Stream](open) started",
|
"Chat.Service.VoiceChatStarted.Channel": "[Live Stream](open) started",
|
||||||
@ -985,6 +987,7 @@ const lang = {
|
|||||||
"NewPoll.Quiz": "Quiz Mode",
|
"NewPoll.Quiz": "Quiz Mode",
|
||||||
"Notification.Contact.Reacted": "%1$@ to your \"%2$@\"",
|
"Notification.Contact.Reacted": "%1$@ to your \"%2$@\"",
|
||||||
// "Notification.Group.Reacted": "%1$@: %2$@ to your \"%3$@\"",
|
// "Notification.Group.Reacted": "%1$@: %2$@ to your \"%3$@\"",
|
||||||
|
"Payments.Recurrent.Accept": "I accept [Terms of Service]() of **%@**.",
|
||||||
"Peer.Activity.User.PlayingGame": "playing a game",
|
"Peer.Activity.User.PlayingGame": "playing a game",
|
||||||
"Peer.Activity.User.TypingText": "typing",
|
"Peer.Activity.User.TypingText": "typing",
|
||||||
"Peer.Activity.User.SendingPhoto": "sending a photo",
|
"Peer.Activity.User.SendingPhoto": "sending a photo",
|
||||||
|
@ -80,6 +80,7 @@ import noop from "../../helpers/noop";
|
|||||||
import DialogsPlaceholder from "../../helpers/dialogsPlaceholder";
|
import DialogsPlaceholder from "../../helpers/dialogsPlaceholder";
|
||||||
import pause from "../../helpers/schedulers/pause";
|
import pause from "../../helpers/schedulers/pause";
|
||||||
import apiManagerProxy from "../mtproto/mtprotoworker";
|
import apiManagerProxy from "../mtproto/mtprotoworker";
|
||||||
|
import filterAsync from "../../helpers/array/filterAsync";
|
||||||
|
|
||||||
export const DIALOG_LIST_ELEMENT_TAG = 'A';
|
export const DIALOG_LIST_ELEMENT_TAG = 'A';
|
||||||
|
|
||||||
@ -1287,10 +1288,12 @@ export class AppDialogsManager {
|
|||||||
|
|
||||||
this.loadContacts = () => {
|
this.loadContacts = () => {
|
||||||
const pageCount = windowSize.height / 60 | 0;
|
const pageCount = windowSize.height / 60 | 0;
|
||||||
const arr = contacts.splice(0, pageCount).filter(this.verifyPeerIdForContacts);
|
const promise = filterAsync(contacts.splice(0, pageCount), this.verifyPeerIdForContacts);
|
||||||
|
|
||||||
arr.forEach((peerId) => {
|
promise.then((arr) => {
|
||||||
sortedUserList.add(peerId);
|
arr.forEach((peerId) => {
|
||||||
|
sortedUserList.add(peerId);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!contacts.length) {
|
if(!contacts.length) {
|
||||||
@ -1300,12 +1303,12 @@ export class AppDialogsManager {
|
|||||||
|
|
||||||
this.loadContacts();
|
this.loadContacts();
|
||||||
|
|
||||||
this.processContact = (peerId) => {
|
this.processContact = async(peerId) => {
|
||||||
if(peerId.isAnyChat()) {
|
if(peerId.isAnyChat()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const good = this.verifyPeerIdForContacts(peerId);
|
const good = await this.verifyPeerIdForContacts(peerId);
|
||||||
const added = sortedUserList.has(peerId);
|
const added = sortedUserList.has(peerId);
|
||||||
if(!added && good) sortedUserList.add(peerId);
|
if(!added && good) sortedUserList.add(peerId);
|
||||||
else if(added && !good) sortedUserList.delete(peerId);
|
else if(added && !good) sortedUserList.delete(peerId);
|
||||||
|
@ -4027,7 +4027,7 @@ export class AppMessagesManager extends AppManager {
|
|||||||
this.onUpdateNewMessage(update);
|
this.onUpdateNewMessage(update);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(message._ === 'messageService' && message.action._ === 'messageActionPaymentSent') {
|
if(message._ === 'messageService' && message.action._ === 'messageActionPaymentSent' && message.reply_to) {
|
||||||
this.rootScope.dispatchEvent('payment_sent', {
|
this.rootScope.dispatchEvent('payment_sent', {
|
||||||
peerId: message.reply_to.reply_to_peer_id ? getPeerId(message.reply_to.reply_to_peer_id) : message.peerId,
|
peerId: message.reply_to.reply_to_peer_id ? getPeerId(message.reply_to.reply_to_peer_id) : message.peerId,
|
||||||
mid: message.reply_to_mid
|
mid: message.reply_to_mid
|
||||||
|
@ -368,6 +368,11 @@ namespace I18n {
|
|||||||
a.target = '_blank';
|
a.target = '_blank';
|
||||||
} else {
|
} else {
|
||||||
a = args[indexHolder.i++] as HTMLAnchorElement;
|
a = args[indexHolder.i++] as HTMLAnchorElement;
|
||||||
|
|
||||||
|
if(a instanceof DocumentFragment) { // right after wrapRichText
|
||||||
|
a = a.firstChild as any;
|
||||||
|
}
|
||||||
|
|
||||||
a.textContent = ''; // reset content
|
a.textContent = ''; // reset content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ export class DcConfigurator {
|
|||||||
|
|
||||||
/// #if MTPROTO_HAS_WS
|
/// #if MTPROTO_HAS_WS
|
||||||
private transportSocket = (dcId: DcId, connectionType: ConnectionType, suffix: string, premium?: boolean) => {
|
private transportSocket = (dcId: DcId, connectionType: ConnectionType, suffix: string, premium?: boolean) => {
|
||||||
const path = connectionType !== 'client' ? 'apiws' + (premium ? PREMIUM_SUFFIX : '') : ('apiws' + TEST_SUFFIX);
|
const path = connectionType !== 'client' ? 'apiws' + (premium ? PREMIUM_SUFFIX : TEST_SUFFIX) : ('apiws' + TEST_SUFFIX);
|
||||||
const chosenServer = `wss://${App.suffix.toLowerCase()}ws${dcId}${suffix}.web.telegram.org/${path}`;
|
const chosenServer = `wss://${App.suffix.toLowerCase()}ws${dcId}${suffix}.web.telegram.org/${path}`;
|
||||||
const logSuffix = connectionType === 'upload' ? '-U' : connectionType === 'download' ? '-D' : '';
|
const logSuffix = connectionType === 'upload' ? '-U' : connectionType === 'download' ? '-D' : '';
|
||||||
|
|
||||||
|
@ -124,6 +124,10 @@
|
|||||||
left: auto;
|
left: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.anchor-url {
|
||||||
|
pointer-events: all;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkbox-ripple {
|
.checkbox-ripple {
|
||||||
|
@ -119,7 +119,9 @@ $row-border-radius: $border-radius-medium;
|
|||||||
}
|
}
|
||||||
|
|
||||||
.checkbox-field {
|
.checkbox-field {
|
||||||
|
margin-top: 0;
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
|
||||||
.checkbox-caption {
|
.checkbox-caption {
|
||||||
|
@ -36,6 +36,8 @@
|
|||||||
|
|
||||||
hr {
|
hr {
|
||||||
display: block !important;
|
display: block !important;
|
||||||
|
margin: .5rem 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-field {
|
.input-field {
|
||||||
@ -158,7 +160,7 @@
|
|||||||
&-prices {
|
&-prices {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin: 1rem .25rem;
|
margin: 1rem .25rem .5rem;
|
||||||
|
|
||||||
&-price {
|
&-price {
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user