UNPKG

zips-react-native-sdk-test

Version:

Lightweight ZIPS Payment Gateway SDK for React Native - Complete payment solution with ZApp wallet payments and Access Bank integration

229 lines (228 loc) 10.7 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useState } from 'react'; import { View, Text, TouchableOpacity, StyleSheet, TextInput, } from 'react-native'; import { Button } from '../common/Button'; import { ShimmerButton } from '../common/Shimmer'; import { useZipsContext } from '../../context/ZipsProvider'; import { useCardContext } from '../../context/CardProvider'; export const CardInput = () => { const { error, isLoading, setCurrentStep } = useZipsContext(); const { cardInformation, setCardInformation } = useCardContext(); const [cardNumber, setCardNumber] = useState(''); const [expiryMonth, setExpiryMonth] = useState(''); const [expiryYear, setExpiryYear] = useState(''); const [cvv, setCvv] = useState(''); const [cardholderName, setCardholderName] = useState(''); const [focusedField, setFocusedField] = useState(null); const formatCardNumber = (value) => { // Remove all non-digits const digits = value.replace(/\D/g, ''); // Add spaces every 4 digits const formatted = digits.replace(/(\d{4})(?=\d)/g, '$1 '); return formatted.substring(0, 19); // Max 16 digits + 3 spaces }; const formatExpiry = (value, isMonth) => { const digits = value.replace(/\D/g, ''); if (isMonth) { return digits.substring(0, 2); } return digits.substring(0, 2); }; const getCardType = (number) => { const digits = number.replace(/\s/g, ''); if (digits.startsWith('4')) return 'Visa'; if (digits.startsWith('5') || (digits.startsWith('2') && digits.length >= 2 && digits.substring(0, 2) >= '22' && digits.substring(0, 2) <= '27')) return 'Mastercard'; if (digits.startsWith('3')) return 'American Express'; return ''; }; const isValidCardNumber = (number) => { const digits = number.replace(/\s/g, ''); return digits.length >= 13 && digits.length <= 19; }; const isValidExpiry = (month, year) => { if (month.length !== 2 || year.length !== 2) return false; const monthNum = parseInt(month, 10); const yearNum = parseInt(year, 10); if (monthNum < 1 || monthNum > 12) return false; const currentDate = new Date(); const currentYear = currentDate.getFullYear() % 100; const currentMonth = currentDate.getMonth() + 1; if (yearNum < currentYear) return false; if (yearNum === currentYear && monthNum < currentMonth) return false; return true; }; const isValidCVV = (cvv, cardType) => { if (cardType === 'American Express') { return cvv.length === 4; } return cvv.length === 3; }; const isFormValid = () => { const cardType = getCardType(cardNumber); return (isValidCardNumber(cardNumber) && isValidExpiry(expiryMonth, expiryYear) && isValidCVV(cvv, cardType) && cardholderName.trim().length >= 2); }; const handleSubmit = () => { if (isFormValid()) { const cardData = { cardNumber: cardNumber.replace(/\s/g, ''), expiryMonth, expiryYear, cvv, cardholderName: cardholderName.trim(), }; setCardInformation(cardData); setCurrentStep('card-confirmation'); } }; const cardType = getCardType(cardNumber); return (_jsxs(View, { style: styles.container, children: [_jsxs(View, { style: styles.header, children: [_jsx(TouchableOpacity, { onPress: () => { setCurrentStep('method-selection'); }, style: styles.backButton, children: _jsx(Text, { style: styles.backButtonText, children: "\u2190 Back" }) }), _jsx(Text, { style: styles.title, children: "Card Payment" }), _jsx(View, { style: styles.placeholder })] }), _jsx(Text, { style: styles.subtitle, children: "Enter your card details to complete the payment" }), error && _jsx(Text, { style: styles.errorText, children: error }), _jsxs(View, { style: styles.inputGroup, children: [_jsx(Text, { style: styles.label, children: "Card Number *" }), _jsxs(View, { style: [ styles.inputContainer, focusedField === 'cardNumber' && styles.inputFocused, ], children: [_jsx(TextInput, { style: styles.input, placeholder: "1234 5678 9012 3456", value: cardNumber, onChangeText: (text) => setCardNumber(formatCardNumber(text)), onFocus: () => setFocusedField('cardNumber'), onBlur: () => setFocusedField(null), keyboardType: "numeric", maxLength: 19, editable: !isLoading, autoCorrect: false, autoCapitalize: "none", returnKeyType: "next", blurOnSubmit: false }), cardType && _jsx(Text, { style: styles.cardIcon, children: cardType })] })] }), _jsxs(View, { style: styles.row, children: [_jsxs(View, { style: [styles.inputGroup, styles.halfWidth], children: [_jsx(Text, { style: styles.label, children: "Expiry Date *" }), _jsxs(View, { style: [ styles.inputContainer, focusedField === 'expiry' && styles.inputFocused, ], children: [_jsx(TextInput, { style: [styles.input, { textAlign: 'center' }], placeholder: "MM", value: expiryMonth, onChangeText: (text) => setExpiryMonth(formatExpiry(text, true)), onFocus: () => setFocusedField('expiry'), keyboardType: "numeric", maxLength: 2, editable: !isLoading, autoCorrect: false, returnKeyType: "next", blurOnSubmit: false }), _jsx(Text, { style: { marginHorizontal: 8, color: '#6B7280' }, children: "/" }), _jsx(TextInput, { style: [styles.input, { textAlign: 'center' }], placeholder: "YY", value: expiryYear, onChangeText: (text) => setExpiryYear(formatExpiry(text, false)), onFocus: () => setFocusedField('expiry'), keyboardType: "numeric", maxLength: 2, editable: !isLoading, autoCorrect: false, returnKeyType: "next", blurOnSubmit: false })] })] }), _jsxs(View, { style: [styles.inputGroup, styles.cvvWidth], children: [_jsx(Text, { style: styles.label, children: "CVV *" }), _jsx(View, { style: [ styles.inputContainer, focusedField === 'cvv' && styles.inputFocused, ], children: _jsx(TextInput, { style: [styles.input, { textAlign: 'center' }], placeholder: cardType === 'American Express' ? '1234' : '123', value: cvv, onChangeText: (text) => setCvv(text.replace(/\D/g, '').substring(0, 4)), onFocus: () => setFocusedField('cvv'), onBlur: () => setFocusedField(null), keyboardType: "numeric", maxLength: cardType === 'American Express' ? 4 : 3, secureTextEntry: true, editable: !isLoading, autoCorrect: false, returnKeyType: "next", blurOnSubmit: false }) })] })] }), _jsxs(View, { style: styles.inputGroup, children: [_jsx(Text, { style: styles.label, children: "Cardholder Name *" }), _jsx(View, { style: [ styles.inputContainer, focusedField === 'name' && styles.inputFocused, ], children: _jsx(TextInput, { style: styles.input, placeholder: "John Doe", value: cardholderName, onChangeText: setCardholderName, onFocus: () => setFocusedField('name'), onBlur: () => setFocusedField(null), autoCapitalize: "words", editable: !isLoading, autoCorrect: false, returnKeyType: "done", blurOnSubmit: true }) })] }), _jsxs(View, { style: styles.securityInfo, children: [_jsx(Text, { style: styles.securityIcon, children: "\uD83D\uDD12" }), _jsx(Text, { style: styles.securityText, children: "Your card details are encrypted and secure" })] }), _jsx(View, { style: styles.actionSection, children: isLoading ? (_jsx(ShimmerButton, {})) : (_jsx(Button, { title: "Continue Payment", onPress: handleSubmit, style: !isFormValid() ? styles.continueButtonDisabled : styles.continueButton, disabled: !isFormValid() })) })] })); }; const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#ffffff', paddingHorizontal: 20, paddingTop: 20, }, header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 24, }, backButton: { paddingVertical: 8, paddingHorizontal: 12, }, backButtonText: { fontSize: 16, color: '#2563eb', fontWeight: '600', }, title: { fontSize: 20, fontWeight: '700', color: '#1e293b', textAlign: 'center', }, placeholder: { width: 60, }, subtitle: { fontSize: 16, color: '#64748b', textAlign: 'center', marginBottom: 30, lineHeight: 24, }, inputGroup: { marginBottom: 20, }, label: { fontSize: 14, fontWeight: '600', color: '#374151', marginBottom: 8, }, inputContainer: { flexDirection: 'row', alignItems: 'center', borderWidth: 2, borderColor: '#E5E7EB', borderRadius: 12, paddingHorizontal: 16, paddingVertical: 14, backgroundColor: '#FFFFFF', }, inputFocused: { borderColor: '#007AFF', backgroundColor: '#F8FAFF', }, input: { flex: 1, fontSize: 16, color: '#1F2937', }, cardIcon: { fontSize: 12, color: '#6B7280', fontWeight: '600', marginLeft: 8, }, row: { flexDirection: 'row', justifyContent: 'space-between', }, halfWidth: { flex: 1, marginRight: 8, }, cvvWidth: { flex: 0.6, marginLeft: 8, }, errorText: { color: '#EF4444', fontSize: 14, marginBottom: 16, textAlign: 'center', }, securityInfo: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', backgroundColor: '#F0FDF4', padding: 12, borderRadius: 8, marginBottom: 32, }, securityIcon: { fontSize: 16, marginRight: 8, }, securityText: { fontSize: 14, color: '#16A34A', fontWeight: '500', }, actionSection: { marginBottom: 24, }, continueButton: { backgroundColor: '#007AFF', borderRadius: 12, }, continueButtonDisabled: { backgroundColor: '#9CA3AF', }, });