import React, { type ChangeEvent, forwardRef, type MouseEvent, type ReactNode, useCallback, useState, } from 'react'; import cn from 'classnames'; import { MaskedInput } from '@alfalab/core-components-masked-input'; import { CameraMIcon } from '@alfalab/icons-glyph/CameraMIcon'; import { MastercardLIcon } from '@alfalab/icons-logotype/MastercardLIcon'; import { MirXxlIcon } from '@alfalab/icons-logotype/MirXxlIcon'; import { VisaXxlIcon } from '@alfalab/icons-logotype/VisaXxlIcon'; import { getDefaultInputLabel } from './helpers/getDefaultInputLabel'; import { DefaultLogo } from './default-logo'; import { MaskTypeEnum } from './enums'; import { type MaskType } from './types'; import { validateCardNumber } from './utils'; import styles from './index.module.css'; export type BankCardProps = { /** * Дополнительный класс */ className?: string; /** * Цвет фона карты */ backgroundColor?: string; /** * Иконка логотипа банка (размер L) */ bankLogo?: ReactNode; /** * Лэйбл поля ввода */ inputLabel?: string; /** * Значение поля ввода */ value?: string; /** * Обработчик ввода */ onChange?: (event: ChangeEvent, payload: { value: string }) => void; /** * Обработчик вызова камеры */ onUsePhoto?: (event: MouseEvent) => void; /** * Идентификатор для систем автоматизированного тестирования */ dataTestId?: string; /** * Тип вводимой маски. Позволяет устанавливать необходимый тип номера (номер карты или номер счёта) * Если параметр не передавать - работает с обоими типами номеров */ maskType?: MaskType; }; // prettier-ignore const cardMask = [/\d/, /\d/, /\d/, /\d/, ' ', /\d/, /\d/, /\d/, /\d/, ' ', /\d/, /\d/, /\d/, /\d/, ' ', /\d/, /\d/, /\d/, /\d/]; // prettier-ignore const accountNumberMask = [/\d/, /\d/, /\d/, /\d/, ' ', /\d/, /\d/, /\d/, /\d/, ' ', /\d/, /\d/, /\d/, /\d/, ' ', /\d/, /\d/, /\d/, /\d/, ' ', /\d/, /\d/, /\d/, /\d/]; const getBrandIcon = (value = '') => { // Показываем логотип только после ввода всех цифр карты if (value.replace(/\s/g, '').length === 16 && validateCardNumber(value)) { if (value.startsWith('2')) return ; if (value.startsWith('4')) return ; if (value.startsWith('5')) return ; if (value.startsWith('6')) return ; } return null; }; export const BankCard = forwardRef( ( { bankLogo = , backgroundColor = '#EF3124', value: valueFromProps, className, onUsePhoto, dataTestId, maskType = MaskTypeEnum.Default, inputLabel = getDefaultInputLabel(maskType), onChange, }, ref, ) => { const uncontrolled = valueFromProps === undefined; const [value, setValue] = useState(valueFromProps); if (!uncontrolled && valueFromProps !== value) { setValue(valueFromProps); } const getMask = useCallback( (newValue: string) => { switch (maskType) { case MaskTypeEnum.Card: return cardMask; case MaskTypeEnum.AccountNumber: return accountNumberMask; case MaskTypeEnum.Default: default: return newValue.length <= cardMask.length ? cardMask : accountNumberMask; } }, [maskType], ); const handleInputChange = useCallback( (event: ChangeEvent, payload: { value: string }) => { onChange?.(event, payload); if (uncontrolled) { setValue(payload.value); } }, [onChange, uncontrolled], ); const renderRightAddons = useCallback( () => ( ), [onUsePhoto], ); const brandIcon = getBrandIcon(value); return (
{bankLogo}
{brandIcon &&
{brandIcon}
}
); }, ); BankCard.displayName = 'BankCard';