Payment Modal: Various fixes (#2124)
This commit is contained in:
parent
f272f63afc
commit
d10df1a705
@ -166,6 +166,7 @@ export interface ApiPoll {
|
||||
export type ApiInputInvoice = {
|
||||
chatId: string;
|
||||
messageId: number;
|
||||
isExtendedMedia?: boolean;
|
||||
} | {
|
||||
slug: string;
|
||||
};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
const VISA = /^4[0-9]{12}(?:[0-9]{1,3})?$/;
|
||||
const MASTERCARD1 = /^5[1-5][0-9]{11,14}$/;
|
||||
const MASTERCARD2 = /^2[2-7][0-9]{11,14}$/;
|
||||
const VISA = /^4\d/;
|
||||
const MASTERCARD1 = /^5[1-5]/;
|
||||
const MASTERCARD2 = /^2[2-7]\d{2}/;
|
||||
const MIR = /^220[0-4]/;
|
||||
|
||||
export enum CardType {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
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, withGlobal } from '../../../global';
|
||||
|
||||
import type { ApiMessage } from '../../../api/types';
|
||||
@ -7,7 +7,6 @@ import type { ApiMessage } from '../../../api/types';
|
||||
import { IS_TOUCH_ENV } from '../../../util/environment';
|
||||
import { selectChatMessage, selectCurrentMessageList } from '../../../global/selectors';
|
||||
import useMouseInside from '../../../hooks/useMouseInside';
|
||||
import useFlag from '../../../hooks/useFlag';
|
||||
|
||||
import Menu from '../../ui/Menu';
|
||||
import Button from '../../ui/Button';
|
||||
@ -31,16 +30,6 @@ const BotKeyboardMenu: FC<OwnProps & StateProps> = ({
|
||||
|
||||
const [handleMouseEnter, handleMouseLeave] = useMouseInside(isOpen, onClose);
|
||||
const { isKeyboardSingleUse } = message || {};
|
||||
const [forceOpen, markForceOpen, unmarkForceOpen] = useFlag(true);
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
unmarkForceOpen();
|
||||
onClose();
|
||||
}, [onClose, unmarkForceOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
markForceOpen();
|
||||
}, [markForceOpen, message?.keyboardButtons]);
|
||||
|
||||
if (!message || !message.keyboardButtons) {
|
||||
return undefined;
|
||||
@ -48,13 +37,13 @@ const BotKeyboardMenu: FC<OwnProps & StateProps> = ({
|
||||
|
||||
return (
|
||||
<Menu
|
||||
isOpen={isOpen || forceOpen}
|
||||
isOpen={isOpen}
|
||||
autoClose={isKeyboardSingleUse}
|
||||
positionX="right"
|
||||
positionY="bottom"
|
||||
onClose={handleClose}
|
||||
onClose={onClose}
|
||||
className="BotKeyboardMenu"
|
||||
onCloseAnimationEnd={handleClose}
|
||||
onCloseAnimationEnd={onClose}
|
||||
onMouseEnter={!IS_TOUCH_ENV ? handleMouseEnter : undefined}
|
||||
onMouseLeave={!IS_TOUCH_ENV ? handleMouseLeave : undefined}
|
||||
noCompact
|
||||
|
||||
@ -56,6 +56,7 @@ const InvoiceMediaPreview: FC<OwnProps> = ({
|
||||
openInvoice({
|
||||
chatId,
|
||||
messageId: id,
|
||||
isExtendedMedia: true,
|
||||
});
|
||||
}, [chatId, id, openInvoice]);
|
||||
|
||||
|
||||
@ -10,6 +10,8 @@ import './ConfirmPayment.scss';
|
||||
|
||||
export type OwnProps = {
|
||||
url: string;
|
||||
noRedirect?: boolean;
|
||||
onClose: NoneToVoidFunction;
|
||||
};
|
||||
|
||||
interface IframeCallbackEvent {
|
||||
@ -19,8 +21,8 @@ interface IframeCallbackEvent {
|
||||
};
|
||||
}
|
||||
|
||||
const ConfirmPayment: FC<OwnProps> = ({ url }) => {
|
||||
const { closePaymentModal, openTelegramLink } = getActions();
|
||||
const ConfirmPayment: FC<OwnProps> = ({ url, noRedirect, onClose }) => {
|
||||
const { openTelegramLink } = getActions();
|
||||
|
||||
const lang = useLang();
|
||||
|
||||
@ -33,13 +35,16 @@ const ConfirmPayment: FC<OwnProps> = ({ url }) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const linkUrl = TME_LINK_PREFIX + eventData.path_full;
|
||||
openTelegramLink({ url: linkUrl });
|
||||
closePaymentModal();
|
||||
if (!noRedirect) {
|
||||
const linkUrl = TME_LINK_PREFIX + eventData.path_full;
|
||||
openTelegramLink({ url: linkUrl });
|
||||
}
|
||||
|
||||
onClose();
|
||||
} catch (err) {
|
||||
// Ignore other messages
|
||||
}
|
||||
}, [closePaymentModal, openTelegramLink]);
|
||||
}, [onClose, noRedirect, openTelegramLink]);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('message', handleMessage);
|
||||
|
||||
@ -4,7 +4,7 @@ $modalHeaderAndFooterHeight: 8.375rem;
|
||||
&.recurring {
|
||||
.Transition {
|
||||
height: 33rem;
|
||||
max-height: calc(90vh - $modalHeaderAndFooterHeight);
|
||||
max-height: calc(92vh - $modalHeaderAndFooterHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ $modalHeaderAndFooterHeight: 8.375rem;
|
||||
}
|
||||
|
||||
.Transition {
|
||||
height: min(27rem, 60vh);
|
||||
height: min(27rem, 68vh);
|
||||
}
|
||||
|
||||
.empty-content {
|
||||
|
||||
@ -39,7 +39,7 @@ const SUPPORTED_PROVIDERS = new Set([DEFAULT_PROVIDER, DONATE_PROVIDER]);
|
||||
|
||||
export type OwnProps = {
|
||||
isOpen?: boolean;
|
||||
onClose: () => void;
|
||||
onClose: NoneToVoidFunction;
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
@ -64,6 +64,7 @@ type StateProps = {
|
||||
stripeId?: string;
|
||||
savedCredentials?: ApiPaymentCredentials[];
|
||||
passwordValidUntil?: number;
|
||||
isExtendedMedia?: boolean;
|
||||
};
|
||||
|
||||
type GlobalStateProps = Pick<GlobalState['payment'], (
|
||||
@ -105,6 +106,7 @@ const PaymentModal: FC<OwnProps & StateProps & GlobalStateProps> = ({
|
||||
stripeId,
|
||||
savedCredentials,
|
||||
passwordValidUntil,
|
||||
isExtendedMedia,
|
||||
}) => {
|
||||
const {
|
||||
loadPasswordInfo,
|
||||
@ -321,6 +323,8 @@ const PaymentModal: FC<OwnProps & StateProps & GlobalStateProps> = ({
|
||||
return (
|
||||
<ConfirmPayment
|
||||
url={confirmPaymentUrl!}
|
||||
noRedirect={isExtendedMedia}
|
||||
onClose={closeModal}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
@ -476,8 +480,27 @@ const PaymentModal: FC<OwnProps & StateProps & GlobalStateProps> = ({
|
||||
? lang('Checkout.PayPrice', formatCurrency(totalPrice, currency!, lang.code))
|
||||
: lang('Next');
|
||||
|
||||
const isSubmitDisabled = isLoading
|
||||
|| Boolean(step === PaymentStep.Checkout && invoice?.isRecurring && !isTosAccepted);
|
||||
function getIsSubmitDisabled() {
|
||||
if (isLoading) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (step) {
|
||||
case PaymentStep.Checkout:
|
||||
return Boolean(invoice?.isRecurring && !isTosAccepted);
|
||||
|
||||
case PaymentStep.PaymentInfo:
|
||||
return Boolean(
|
||||
paymentState.cardNumber === ''
|
||||
|| (needCardholderName && paymentState.cardholder === '')
|
||||
|| paymentState.cvv === ''
|
||||
|| paymentState.expiry === '',
|
||||
);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isProviderError) {
|
||||
return (
|
||||
@ -501,6 +524,8 @@ const PaymentModal: FC<OwnProps & StateProps & GlobalStateProps> = ({
|
||||
);
|
||||
}
|
||||
|
||||
const isSubmitDisabled = getIsSubmitDisabled();
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className={buildClassName('PaymentModal', invoice?.isRecurring && 'recurring')}
|
||||
@ -569,6 +594,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
smartGlocalCredentials,
|
||||
savedCredentials,
|
||||
temporaryPassword,
|
||||
isExtendedMedia,
|
||||
} = global.payment;
|
||||
|
||||
const chat = inputInvoice && 'chatId' in inputInvoice ? selectChat(global, inputInvoice.chatId) : undefined;
|
||||
@ -615,6 +641,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
stripeId: stripeCredentials?.id,
|
||||
savedCredentials,
|
||||
passwordValidUntil: temporaryPassword?.validUntil,
|
||||
isExtendedMedia,
|
||||
};
|
||||
},
|
||||
)(PaymentModal));
|
||||
|
||||
@ -144,7 +144,7 @@
|
||||
flex-grow: 1;
|
||||
padding: 1rem;
|
||||
overflow-y: auto;
|
||||
max-height: 90vh;
|
||||
max-height: 92vh;
|
||||
|
||||
b,
|
||||
strong {
|
||||
|
||||
@ -25,7 +25,6 @@ import {
|
||||
setPaymentForm,
|
||||
setStripeCardInfo,
|
||||
setReceipt,
|
||||
clearPayment,
|
||||
closeInvoice,
|
||||
setSmartGlocalCardInfo, addUsers, setInvoiceInfo, updatePayment,
|
||||
} from '../../reducers';
|
||||
@ -82,6 +81,7 @@ addActionHandler('openInvoice', async (global, actions, payload) => {
|
||||
inputInvoice: payload,
|
||||
isPaymentModalOpen: true,
|
||||
status: 'cancelled',
|
||||
isExtendedMedia: (payload as any).isExtendedMedia,
|
||||
},
|
||||
});
|
||||
});
|
||||
@ -217,7 +217,6 @@ addActionHandler('sendPaymentForm', async (global, actions, payload) => {
|
||||
}
|
||||
|
||||
global = getGlobal();
|
||||
global = clearPayment(global);
|
||||
global = updatePayment(global, { status: 'paid' });
|
||||
global = closeInvoice(global);
|
||||
setGlobal(global);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { addActionHandler } from '../../index';
|
||||
|
||||
import { IS_PRODUCTION_HOST } from '../../../util/environment';
|
||||
import { clearPayment } from '../../reducers';
|
||||
import { closeInvoice } from '../../reducers';
|
||||
import * as langProvider from '../../../util/langProvider';
|
||||
import { formatCurrency } from '../../../util/formatCurrency';
|
||||
import { selectChatMessage } from '../../selectors';
|
||||
@ -28,8 +28,9 @@ addActionHandler('apiUpdate', (global, actions, update) => {
|
||||
|
||||
// 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.
|
||||
// Closing the invoice will cause the closing of the Payment Modal dialog and then closing the payment.
|
||||
if (!IS_PRODUCTION_HOST) {
|
||||
global = clearPayment(global);
|
||||
global = closeInvoice(global);
|
||||
}
|
||||
|
||||
if (update.slug && inputInvoice && 'slug' in inputInvoice && inputInvoice.slug !== update.slug) {
|
||||
|
||||
@ -110,5 +110,5 @@ export function clearPayment(global: GlobalState): GlobalState {
|
||||
}
|
||||
|
||||
export function closeInvoice(global: GlobalState): GlobalState {
|
||||
return updatePayment(global, { isPaymentModalOpen: undefined });
|
||||
return updatePayment(global, { isPaymentModalOpen: undefined, isExtendedMedia: undefined });
|
||||
}
|
||||
|
||||
@ -504,6 +504,7 @@ export type GlobalState = {
|
||||
description?: string;
|
||||
};
|
||||
isPaymentModalOpen?: boolean;
|
||||
isExtendedMedia?: boolean;
|
||||
confirmPaymentUrl?: string;
|
||||
temporaryPassword?: {
|
||||
value: string;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user