Payment Modal: Fix scroll and card info validation (#1944)

This commit is contained in:
Alexander Zinchuk 2022-07-08 15:00:34 +02:00
parent e841738112
commit 63c150ddd8
5 changed files with 22 additions and 25 deletions

View File

@ -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>

View File

@ -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
/> />
); );
}; };

View File

@ -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}
/> />
)} )}

View File

@ -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;
} }
} }

View File

@ -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>