pagamio-frontend-commons-lib
Version:
Pagamio library for Frontend reusable components like the form engine and table container
83 lines (82 loc) • 5.4 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { forwardRef, useCallback, useEffect, useState } from 'react';
import { Input } from '../../../../components';
const CARD_PATTERNS = {
visa: '4',
mastercard: {
twoDigitPrefixes: ['51', '52', '53', '54', '55'],
fourDigitPrefixStart: '2',
fourDigitSecondMin: 2,
fourDigitSecondMax: 7,
fourDigitThirdMin: 2,
fourDigitThirdMax: 9,
},
};
// SVG icons for card types
const CardIcons = {
visa: (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 48 48", width: "24px", height: "24px", children: [_jsx("path", { fill: "#1565C0", d: "M45,35c0,2.209-1.791,4-4,4H7c-2.209,0-4-1.791-4-4V13c0-2.209,1.791-4,4-4h34c2.209,0,4,1.791,4,4V35z" }), _jsx("path", { fill: "#FFF", d: "M15.186 19l-2.626 7.832c0 0-.667-3.313-.733-3.729-1.495-3.411-3.701-3.221-3.701-3.221L10.726 30v-.002h3.161L18.258 19H15.186zM17.689 30L20.56 30 22.296 19 19.389 19zM38.008 19h-3.021l-4.71 11h2.852l.588-1.571h3.596L37.619 30h2.613L38.008 19zM34.513 26.328l1.563-4.157.818 4.157H34.513zM26.369 22.206c0-.606.498-1.057 1.926-1.057.928 0 1.991.674 1.991.674l.466-2.309c0 0-1.358-.515-2.691-.515-3.019 0-4.576 1.444-4.576 3.272 0 3.306 3.979 2.853 3.979 4.551 0 .291-.231.964-1.888.964-1.662 0-2.759-.609-2.759-.609l-.495 2.216c0 0 1.063.606 3.117.606 2.059 0 4.915-1.54 4.915-3.752C30.354 23.586 26.369 23.394 26.369 22.206z" }), _jsx("path", { fill: "#FFC107", d: "M12.212,24.945l-0.966-4.748c0,0-0.437-1.029-1.573-1.029c-1.136,0-4.44,0-4.44,0S10.894,20.84,12.212,24.945z" })] })),
mastercard: (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 48 48", width: "35px", height: "35px", children: [_jsx("path", { fill: "#ff9800", d: "M32 10A14 14 0 1 0 32 38A14 14 0 1 0 32 10Z" }), _jsx("path", { fill: "#d50000", d: "M16 10A14 14 0 1 0 16 38A14 14 0 1 0 16 10Z" }), _jsx("path", { fill: "#ff3d00", d: "M18,24c0,4.755,2.376,8.95,6,11.48c3.624-2.53,6-6.725,6-11.48s-2.376-8.95-6-11.48 C20.376,15.05,18,19.245,18,24z" })] })),
};
const CreditCardInput = forwardRef(({ field, error, onChange, value, ...props }, ref) => {
const [cardType, setCardType] = useState(null);
const [formattedValue, setFormattedValue] = useState('');
// Format card number with spaces
const formatCardNumber = useCallback((input) => {
const numbers = input.replace(/\D/g, '');
const groups = numbers.match(/.{1,4}/g) || [];
return groups.join(' ');
}, []);
// Detect card type
const detectCardType = useCallback((input) => {
const numbers = input.replace(/\D/g, '');
// Check Visa (starts with 4)
if (numbers.startsWith(CARD_PATTERNS.visa))
return 'visa';
// Check Mastercard
if (
// Check 51-55 prefixes
CARD_PATTERNS.mastercard.twoDigitPrefixes.some((prefix) => numbers.startsWith(prefix)) ||
// Check 222x-279x prefixes
(numbers.length >= 4 &&
numbers.startsWith(CARD_PATTERNS.mastercard.fourDigitPrefixStart) &&
Number(numbers[1]) >= CARD_PATTERNS.mastercard.fourDigitSecondMin &&
Number(numbers[1]) <= CARD_PATTERNS.mastercard.fourDigitSecondMax &&
Number(numbers[2]) >= CARD_PATTERNS.mastercard.fourDigitThirdMin &&
Number(numbers[2]) <= CARD_PATTERNS.mastercard.fourDigitThirdMax)) {
return 'mastercard';
}
return null;
}, []);
// Handle input change
const handleChange = useCallback((e) => {
const input = e.target.value;
const numbers = input.replace(/\D/g, '');
if (numbers.length > 16)
return;
const formatted = formatCardNumber(numbers);
const type = detectCardType(numbers);
setFormattedValue(formatted);
setCardType(type);
// Call parent onChange with raw numeric value
if (onChange) {
const event = {
...e,
target: {
...e.target,
value: numbers,
},
};
onChange(event);
}
}, [formatCardNumber, detectCardType, onChange]);
// Initialize formatted value when value prop changes
useEffect(() => {
if (value) {
setFormattedValue(formatCardNumber(value.toString()));
setCardType(detectCardType(value.toString()));
}
}, [value, formatCardNumber, detectCardType]);
return (_jsxs("div", { className: "relative", children: [_jsx("label", { htmlFor: field.name, className: "block text-sm font-medium text-gray-700", children: field.label }), _jsxs("div", { className: "relative", children: [_jsx(Input, { ...props, id: field.name, ref: ref, type: "creditCard", value: formattedValue, onChange: handleChange, disabled: field.disabled, placeholder: field.placeholder ?? '4242 4242 4242 4242', className: `mt-1 block w-full p-2 border ${error ? 'border-red-500' : 'border-gray-300'} rounded-md shadow-sm disabled:text-gray-400 disabled:bg-gray-50 pr-12` }), _jsx("div", { className: "absolute right-3 top-1/2 -translate-y-1/2", children: cardType && CardIcons[cardType] })] }), error && _jsx("p", { className: "mt-2 text-sm text-red-500", children: error.message })] }));
});
CreditCardInput.displayName = 'CreditCardInput';
export default CreditCardInput;