Payment: Support closing form by event from t.me (#1983)

This commit is contained in:
Alexander Zinchuk 2022-08-05 19:23:25 +02:00
parent afd0a00730
commit 0b3db96ea2
11 changed files with 64 additions and 19 deletions

View File

@ -1206,11 +1206,11 @@ function preparePeers(
) { ) {
const store: Record<string, GramJs.TypeChat | GramJs.TypeUser> = {}; const store: Record<string, GramJs.TypeChat | GramJs.TypeUser> = {};
result.chats.forEach((chat) => { result.chats?.forEach((chat) => {
store[`chat${chat.id}`] = chat; store[`chat${chat.id}`] = chat;
}); });
result.users.forEach((user) => { result.users?.forEach((user) => {
store[`user${user.id}`] = user; store[`user${user.id}`] = user;
}); });

View File

@ -4,6 +4,7 @@ import React, {
useState, useCallback, memo, useEffect, useMemo, useState, useCallback, memo, useEffect, useMemo,
} from '../../lib/teact/teact'; } from '../../lib/teact/teact';
import { TME_LINK_PREFIX } from '../../config';
import { debounce } from '../../util/schedulers'; import { debounce } from '../../util/schedulers';
import useLang from '../../hooks/useLang'; import useLang from '../../hooks/useLang';
@ -20,7 +21,6 @@ type OwnProps = {
const MIN_USERNAME_LENGTH = 5; const MIN_USERNAME_LENGTH = 5;
const MAX_USERNAME_LENGTH = 32; const MAX_USERNAME_LENGTH = 32;
const LINK_PREFIX = 'https://t.me/';
const LINK_PREFIX_REGEX = /https:\/\/t\.me\/?/i; const LINK_PREFIX_REGEX = /https:\/\/t\.me\/?/i;
const USERNAME_REGEX = /^([a-zA-Z0-9_]+)$/; const USERNAME_REGEX = /^([a-zA-Z0-9_]+)$/;
@ -79,7 +79,7 @@ const SettingsEditProfile: FC<OwnProps> = ({
const handleUsernameChange = useCallback((e: ChangeEvent<HTMLInputElement>) => { const handleUsernameChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
const newUsername = e.target.value.trim().replace(LINK_PREFIX_REGEX, ''); const newUsername = e.target.value.trim().replace(LINK_PREFIX_REGEX, '');
setUsername(newUsername); setUsername(newUsername);
e.target.value = `${asLink ? LINK_PREFIX : ''}${newUsername}`; e.target.value = `${asLink ? TME_LINK_PREFIX : ''}${newUsername}`;
const isValid = isUsernameValid(newUsername); const isValid = isUsernameValid(newUsername);
@ -96,7 +96,7 @@ const SettingsEditProfile: FC<OwnProps> = ({
return ( return (
<InputText <InputText
value={`${asLink ? LINK_PREFIX : ''}${username}`} value={`${asLink ? TME_LINK_PREFIX : ''}${username}`}
onChange={handleUsernameChange} onChange={handleUsernameChange}
label={label} label={label}
error={usernameError} error={usernameError}

View File

@ -15,6 +15,7 @@ import {
FEEDBACK_URL, FEEDBACK_URL,
IS_BETA, IS_BETA,
IS_TEST, IS_TEST,
PRODUCTION_HOSTNAME,
} from '../../../config'; } from '../../../config';
import { IS_PWA, IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment'; import { IS_PWA, IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
@ -70,7 +71,6 @@ type StateProps =
} }
& Pick<GlobalState, 'connectionState' | 'isSyncing' | 'canInstall'>; & Pick<GlobalState, 'connectionState' | 'isSyncing' | 'canInstall'>;
const PRODUCTION_HOSTNAME = 'web.telegram.org';
const LEGACY_VERSION_URL = 'https://web.telegram.org/?legacy=1'; const LEGACY_VERSION_URL = 'https://web.telegram.org/?legacy=1';
const WEBK_VERSION_URL = 'https://web.telegram.org/k/'; const WEBK_VERSION_URL = 'https://web.telegram.org/k/';

View File

@ -10,6 +10,7 @@ import type { ThemeKey } from '../../types';
import windowSize from '../../util/windowSize'; import windowSize from '../../util/windowSize';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment'; import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
import { TME_LINK_PREFIX } from '../../config';
import { selectCurrentChat, selectTheme, selectUser } from '../../global/selectors'; import { selectCurrentChat, selectTheme, selectUser } from '../../global/selectors';
import buildClassName from '../../util/buildClassName'; import buildClassName from '../../util/buildClassName';
import { extractCurrentThemeParams, validateHexColor } from '../../util/themeStyle'; import { extractCurrentThemeParams, validateHexColor } from '../../util/themeStyle';
@ -54,7 +55,6 @@ type StateProps = {
const MAIN_BUTTON_ANIMATION_TIME = 250; const MAIN_BUTTON_ANIMATION_TIME = 250;
const PROLONG_INTERVAL = 45000; // 45s const PROLONG_INTERVAL = 45000; // 45s
const ANIMATION_WAIT = 400; const ANIMATION_WAIT = 400;
const LINK_PREFIX = 'https://t.me/';
const SANDBOX_ATTRIBUTES = [ const SANDBOX_ATTRIBUTES = [
'allow-scripts', 'allow-scripts',
'allow-same-origin', 'allow-same-origin',
@ -110,7 +110,7 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
} }
if (eventType === 'web_app_open_tg_link') { if (eventType === 'web_app_open_tg_link') {
const linkUrl = LINK_PREFIX + eventData.path_full; const linkUrl = TME_LINK_PREFIX + eventData.path_full;
openTelegramLink({ url: linkUrl }); openTelegramLink({ url: linkUrl });
closeWebApp(); closeWebApp();
} }

View File

@ -12,6 +12,7 @@ import PremiumFeatureModal, {
PREMIUM_FEATURE_SECTIONS, PREMIUM_FEATURE_SECTIONS,
PREMIUM_FEATURE_TITLES, PREMIUM_FEATURE_TITLES,
} from './PremiumFeatureModal'; } from './PremiumFeatureModal';
import { TME_LINK_PREFIX } from '../../../config';
import { formatCurrency } from '../../../util/formatCurrency'; import { formatCurrency } from '../../../util/formatCurrency';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import { selectIsCurrentUserPremium, selectUser } from '../../../global/selectors'; import { selectIsCurrentUserPremium, selectUser } from '../../../global/selectors';
@ -77,8 +78,6 @@ type StateProps = {
premiumBotUsername?: string; premiumBotUsername?: string;
}; };
const LINK_PREFIX = 'https://t.me/';
const PremiumMainModal: FC<OwnProps & StateProps> = ({ const PremiumMainModal: FC<OwnProps & StateProps> = ({
isOpen, isOpen,
fromUser, fromUser,
@ -127,7 +126,7 @@ const PremiumMainModal: FC<OwnProps & StateProps> = ({
}); });
} else if (premiumBotUsername) { } else if (premiumBotUsername) {
openTelegramLink({ openTelegramLink({
url: `${LINK_PREFIX}${premiumBotUsername}?start=${startParam || 'promo'}`, url: `${TME_LINK_PREFIX}${premiumBotUsername}?start=${startParam || 'promo'}`,
}); });
closePremiumModal(); closePremiumModal();
} }

View File

@ -20,7 +20,7 @@ import {
isActionMessage, isChatChannel, isActionMessage, isChatChannel,
isChatGroup, isOwnMessage, areReactionsEmpty, isUserId, isMessageLocal, getMessageVideo, isChatGroup, isOwnMessage, areReactionsEmpty, isUserId, isMessageLocal, getMessageVideo,
} from '../../../global/helpers'; } from '../../../global/helpers';
import { SERVICE_NOTIFICATIONS_USER_ID } from '../../../config'; import { SERVICE_NOTIFICATIONS_USER_ID, TME_LINK_PREFIX } from '../../../config';
import { getDayStartAt } from '../../../util/dateFormat'; import { getDayStartAt } from '../../../util/dateFormat';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import { REM } from '../../common/helpers/mediaDimensions'; import { REM } from '../../common/helpers/mediaDimensions';
@ -326,7 +326,7 @@ const ContextMenuContainer: FC<OwnProps & StateProps> = ({
}, [closeMenu, copyMessagesByIds]); }, [closeMenu, copyMessagesByIds]);
const handleCopyLink = useCallback(() => { const handleCopyLink = useCallback(() => {
copyTextToClipboard(`https://t.me/${chatUsername || `c/${message.chatId.replace('-', '')}`}/${message.id}`); copyTextToClipboard(`${TME_LINK_PREFIX}${chatUsername || `c/${message.chatId.replace('-', '')}`}/${message.id}`);
closeMenu(); closeMenu();
}, [chatUsername, closeMenu, message]); }, [chatUsername, closeMenu, message]);

View File

@ -1,6 +1,9 @@
import type { FC } from '../../lib/teact/teact'; import React, { memo, useCallback, useEffect } from '../../lib/teact/teact';
import React, { memo } from '../../lib/teact/teact'; import { getActions } from '../../global';
import type { FC } from '../../lib/teact/teact';
import { TME_LINK_PREFIX } from '../../config';
import useLang from '../../hooks/useLang'; import useLang from '../../hooks/useLang';
import './ConfirmPayment.scss'; import './ConfirmPayment.scss';
@ -9,16 +12,47 @@ export type OwnProps = {
url: string; url: string;
}; };
interface IframeCallbackEvent {
eventType: string;
eventData: {
path_full: string;
};
}
const ConfirmPayment: FC<OwnProps> = ({ url }) => { const ConfirmPayment: FC<OwnProps> = ({ url }) => {
const { closePaymentModal, openTelegramLink } = getActions();
const lang = useLang(); const lang = useLang();
const handleMessage = useCallback((event: MessageEvent<string>) => {
try {
const data = JSON.parse(event.data) as IframeCallbackEvent;
const { eventType, eventData } = data;
if (eventType !== 'web_app_open_tg_link') {
return;
}
const linkUrl = TME_LINK_PREFIX + eventData.path_full;
openTelegramLink({ url: linkUrl });
closePaymentModal();
} catch (err) {
// Ignore other messages
}
}, [closePaymentModal, openTelegramLink]);
useEffect(() => {
window.addEventListener('message', handleMessage);
return () => window.removeEventListener('message', handleMessage);
}, [handleMessage]);
return ( return (
<div className="ConfirmPayment"> <div className="ConfirmPayment">
<iframe <iframe
src={url} src={url}
title={lang('Checkout.WebConfirmation.Title')} title={lang('Checkout.WebConfirmation.Title')}
allow="payment" allow="payment"
sandbox="allow-forms allow-scripts allow-same-origin allow-top-navigation" sandbox="allow-modals allow-forms allow-scripts allow-same-origin allow-top-navigation"
className="ConfirmPayment__content" className="ConfirmPayment__content"
/> />
</div> </div>

View File

@ -3,6 +3,8 @@ import type { ApiLimitType } from './global/types';
export const APP_NAME = process.env.APP_NAME || 'Telegram WebZ'; export const APP_NAME = process.env.APP_NAME || 'Telegram WebZ';
export const APP_VERSION = process.env.APP_VERSION!; export const APP_VERSION = process.env.APP_VERSION!;
export const PRODUCTION_HOSTNAME = 'web.telegram.org';
export const DEBUG = process.env.APP_ENV !== 'production'; export const DEBUG = process.env.APP_ENV !== 'production';
export const DEBUG_MORE = false; export const DEBUG_MORE = false;
@ -191,6 +193,7 @@ export const RE_MENTION_TEMPLATE = '(@[\\w\\d_-]+)';
export const RE_TG_LINK = /^tg:(\/\/)?([?=&\d\w_-]+)?/gm; export const RE_TG_LINK = /^tg:(\/\/)?([?=&\d\w_-]+)?/gm;
export const RE_TME_LINK = /^(?:https?:\/\/)?(?:t\.me\/)/gm; export const RE_TME_LINK = /^(?:https?:\/\/)?(?:t\.me\/)/gm;
export const RE_TELEGRAM_LINK = /^(?:https?:\/\/)?(?:telegram\.org\/)/gm; export const RE_TELEGRAM_LINK = /^(?:https?:\/\/)?(?:telegram\.org\/)/gm;
export const TME_LINK_PREFIX = 'https://t.me/';
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
export const COUNTRIES_WITH_12H_TIME_FORMAT = new Set(['AU', 'BD', 'CA', 'CO', 'EG', 'HN', 'IE', 'IN', 'JO', 'MX', 'MY', 'NI', 'NZ', 'PH', 'PK', 'SA', 'SV', 'US']); export const COUNTRIES_WITH_12H_TIME_FORMAT = new Set(['AU', 'BD', 'CA', 'CO', 'EG', 'HN', 'IE', 'IN', 'JO', 'MX', 'MY', 'NI', 'NZ', 'PH', 'PK', 'SA', 'SV', 'US']);

View File

@ -1,5 +1,6 @@
import { addActionHandler } from '../../index'; import { addActionHandler } from '../../index';
import { IS_PRODUCTION_HOST } from '../../../util/environment';
import { clearPayment } from '../../reducers'; import { clearPayment } from '../../reducers';
addActionHandler('apiUpdate', (global, actions, update) => { addActionHandler('apiUpdate', (global, actions, update) => {
@ -9,7 +10,13 @@ addActionHandler('apiUpdate', (global, actions, update) => {
if (update.slug && inputInvoice && 'slug' in inputInvoice && inputInvoice.slug !== update.slug) { if (update.slug && inputInvoice && 'slug' in inputInvoice && inputInvoice.slug !== update.slug) {
return undefined; return undefined;
} }
// On the production host, the payment frame receives a message with the payment event,
// after which the payment form closes. In other cases, the payment form must be closed manually.
if (!IS_PRODUCTION_HOST) {
global = clearPayment(global); global = clearPayment(global);
}
return { return {
...global, ...global,
payment: { payment: {

View File

@ -12,7 +12,7 @@ import {
import type { NotifyException, NotifySettings } from '../../types'; import type { NotifyException, NotifySettings } from '../../types';
import type { LangFn } from '../../hooks/useLang'; import type { LangFn } from '../../hooks/useLang';
import { ARCHIVED_FOLDER_ID, REPLIES_USER_ID } from '../../config'; import { ARCHIVED_FOLDER_ID, REPLIES_USER_ID, TME_LINK_PREFIX } from '../../config';
import { orderBy } from '../../util/iteratees'; import { orderBy } from '../../util/iteratees';
import { getUserFirstOrLastName } from './users'; import { getUserFirstOrLastName } from './users';
import { formatDateToString, formatTime } from '../../util/dateFormat'; import { formatDateToString, formatTime } from '../../util/dateFormat';
@ -96,7 +96,7 @@ export function getChatDescription(chat: ApiChat) {
export function getChatLink(chat: ApiChat) { export function getChatLink(chat: ApiChat) {
const { username } = chat; const { username } = chat;
if (username) { if (username) {
return `https://t.me/${username}`; return `${TME_LINK_PREFIX}${username}`;
} }
const { inviteLink } = chat.fullInfo || {}; const { inviteLink } = chat.fullInfo || {};

View File

@ -7,6 +7,7 @@ import {
SUPPORTED_VIDEO_CONTENT_TYPES, SUPPORTED_VIDEO_CONTENT_TYPES,
VIDEO_MOV_TYPE, VIDEO_MOV_TYPE,
CONTENT_TYPES_WITH_PREVIEW, CONTENT_TYPES_WITH_PREVIEW,
PRODUCTION_HOSTNAME,
} from '../config'; } from '../config';
export * from './environmentWebp'; export * from './environmentWebp';
@ -35,6 +36,7 @@ export function getPlatform() {
return os; return os;
} }
export const IS_PRODUCTION_HOST = window.location.host === PRODUCTION_HOSTNAME;
export const PLATFORM_ENV = getPlatform(); export const PLATFORM_ENV = getPlatform();
export const IS_MAC_OS = PLATFORM_ENV === 'macOS'; export const IS_MAC_OS = PLATFORM_ENV === 'macOS';
export const IS_IOS = PLATFORM_ENV === 'iOS'; export const IS_IOS = PLATFORM_ENV === 'iOS';