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
JavaScript
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',
},
});