Payment Modal: Fix scroll and card info validation (#1944)
This commit is contained in:
parent
e841738112
commit
63c150ddd8
@ -42,10 +42,7 @@ const CardInput : FC<OwnProps> = ({ value, error, onChange }) => {
|
|||||||
const newCardType = detectCardType(e.target.value);
|
const newCardType = detectCardType(e.target.value);
|
||||||
setCardType(newCardType);
|
setCardType(newCardType);
|
||||||
onChange(newValue);
|
onChange(newValue);
|
||||||
if (cardNumberRef.current) {
|
}, [onChange]);
|
||||||
cardNumberRef.current.value = newValue;
|
|
||||||
}
|
|
||||||
}, [onChange, cardNumberRef]);
|
|
||||||
|
|
||||||
const cardIcon = getCardIcon(cardType);
|
const cardIcon = getCardIcon(cardType);
|
||||||
|
|
||||||
@ -61,6 +58,7 @@ const CardInput : FC<OwnProps> = ({ value, error, onChange }) => {
|
|||||||
error={error}
|
error={error}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
maxLength={CARD_NUMBER_MAX_LENGTH}
|
maxLength={CARD_NUMBER_MAX_LENGTH}
|
||||||
|
teactExperimentControlled
|
||||||
/>
|
/>
|
||||||
<span className="right-addon">{cardIcon}</span>
|
<span className="right-addon">{cardIcon}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import type { FC } from '../../lib/teact/teact';
|
import type { FC } from '../../lib/teact/teact';
|
||||||
import React, { memo, useCallback, useRef } from '../../lib/teact/teact';
|
import React, { memo, useCallback } from '../../lib/teact/teact';
|
||||||
|
|
||||||
import { formatCardExpiry } from '../middle/helpers/inputFormatters';
|
import { formatCardExpiry } from '../middle/helpers/inputFormatters';
|
||||||
|
|
||||||
@ -16,33 +16,27 @@ export type OwnProps = {
|
|||||||
|
|
||||||
const ExpiryInput : FC<OwnProps> = ({ value, error, onChange }) => {
|
const ExpiryInput : FC<OwnProps> = ({ value, error, onChange }) => {
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
// eslint-disable-next-line no-null/no-null
|
|
||||||
const expiryInputRef = useRef<HTMLInputElement>(null);
|
|
||||||
|
|
||||||
const handleKeyDown = useCallback((e) => {
|
|
||||||
if (e.key === 'Backspace' && value.charAt(value.length - 1) === '/') {
|
|
||||||
const newValue = value.slice(0, value.length - 1);
|
|
||||||
if (expiryInputRef.current) {
|
|
||||||
expiryInputRef.current.value = newValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [value]);
|
|
||||||
|
|
||||||
const handleChange = useCallback((e) => {
|
const handleChange = useCallback((e) => {
|
||||||
onChange(formatCardExpiry(e.target.value));
|
const newValue = e.target.value;
|
||||||
}, [onChange]);
|
// Allow deleting separator
|
||||||
|
if (value.endsWith('/') && value.length > newValue.length) {
|
||||||
|
onChange(newValue);
|
||||||
|
} else {
|
||||||
|
onChange(formatCardExpiry(e.target.value));
|
||||||
|
}
|
||||||
|
}, [onChange, value]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InputText
|
<InputText
|
||||||
label={lang('PaymentCardExpireDate')}
|
label={lang('PaymentCardExpireDate')}
|
||||||
ref={expiryInputRef}
|
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onKeyDown={handleKeyDown}
|
|
||||||
value={value}
|
value={value}
|
||||||
error={error}
|
error={error}
|
||||||
inputMode="numeric"
|
inputMode="numeric"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
maxLength={MAX_FIELD_LENGTH}
|
maxLength={MAX_FIELD_LENGTH}
|
||||||
|
teactExperimentControlled
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -58,7 +58,8 @@ const PaymentInfo: FC<OwnProps> = ({
|
|||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
const handleCvvChange = useCallback((e) => {
|
const handleCvvChange = useCallback((e) => {
|
||||||
dispatch({ type: 'changeCvvCode', payload: e.target.value });
|
const newValue = e.target.value.replace(/[^0-9]/g, '');
|
||||||
|
dispatch({ type: 'changeCvvCode', payload: newValue });
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
const handleCountryChange = useCallback((e) => {
|
const handleCountryChange = useCallback((e) => {
|
||||||
@ -110,6 +111,7 @@ const PaymentInfo: FC<OwnProps> = ({
|
|||||||
maxLength={3}
|
maxLength={3}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
error={formErrors.cvv}
|
error={formErrors.cvv}
|
||||||
|
teactExperimentControlled
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
{ needCountry || needZip ? (
|
{ needCountry || needZip ? (
|
||||||
@ -147,6 +149,7 @@ const PaymentInfo: FC<OwnProps> = ({
|
|||||||
value={state.billingZip}
|
value={state.billingZip}
|
||||||
inputMode="text"
|
inputMode="text"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
|
maxLength={12}
|
||||||
error={formErrors.billingZip}
|
error={formErrors.billingZip}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -30,7 +30,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.Transition {
|
.Transition {
|
||||||
height: 25rem;
|
height: min(25rem, 60vh);
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-content {
|
.empty-content {
|
||||||
@ -54,7 +54,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
position: absolute;
|
position: relative;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
border-bottom-left-radius: var(--border-radius-default-small);
|
border-bottom-left-radius: var(--border-radius-default-small);
|
||||||
border-bottom-right-radius: var(--border-radius-default-small);
|
border-bottom-right-radius: var(--border-radius-default-small);
|
||||||
@ -75,8 +75,7 @@
|
|||||||
|
|
||||||
.modal-content {
|
.modal-content {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
overflow: auto;
|
overflow: hidden;
|
||||||
overflow: overlay;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,7 @@ type OwnProps = {
|
|||||||
autoComplete?: string;
|
autoComplete?: string;
|
||||||
maxLength?: number;
|
maxLength?: number;
|
||||||
tabIndex?: number;
|
tabIndex?: number;
|
||||||
|
teactExperimentControlled?: boolean;
|
||||||
inputMode?: 'text' | 'none' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search';
|
inputMode?: 'text' | 'none' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search';
|
||||||
onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
|
onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
|
||||||
onInput?: (e: FormEvent<HTMLInputElement>) => void;
|
onInput?: (e: FormEvent<HTMLInputElement>) => void;
|
||||||
@ -45,6 +46,7 @@ const InputText: FC<OwnProps> = ({
|
|||||||
inputMode,
|
inputMode,
|
||||||
maxLength,
|
maxLength,
|
||||||
tabIndex,
|
tabIndex,
|
||||||
|
teactExperimentControlled,
|
||||||
onChange,
|
onChange,
|
||||||
onInput,
|
onInput,
|
||||||
onKeyPress,
|
onKeyPress,
|
||||||
@ -87,6 +89,7 @@ const InputText: FC<OwnProps> = ({
|
|||||||
onBlur={onBlur}
|
onBlur={onBlur}
|
||||||
onPaste={onPaste}
|
onPaste={onPaste}
|
||||||
aria-label={labelText}
|
aria-label={labelText}
|
||||||
|
teactExperimentControlled={teactExperimentControlled}
|
||||||
/>
|
/>
|
||||||
{labelText && (
|
{labelText && (
|
||||||
<label htmlFor={id}>{labelText}</label>
|
<label htmlFor={id}>{labelText}</label>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user