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

270 lines (269 loc) 10.3 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useState } from 'react'; import { View, Text, TextInput, TouchableOpacity, StyleSheet, Image, } from 'react-native'; import { Button } from '../common/Button'; import { ShimmerButton } from '../common/Shimmer'; import { useWalletContext } from '../../context/WalletProvider'; import { useZipsContext } from '../../context/ZipsProvider'; export const WalletInput = () => { const { paymentDetails, setCurrentStep } = useZipsContext(); const { selectedWallet, error, isLoading } = useWalletContext(); const [phoneNumber, setPhoneNumber] = useState(''); const [pin, setPin] = useState(''); const [phoneError, setPhoneError] = useState(''); const [pinError, setPinError] = useState(''); const validatePhoneNumber = (phone) => { // Gambian phone number validation (7 digits) const gambianPhoneRegex = /^[0-9]{7}$/; return gambianPhoneRegex.test(phone); }; const validatePin = (pinValue) => { // PIN should be 4-6 digits const pinRegex = /^[0-9]{4,6}$/; return pinRegex.test(pinValue); }; const formatPhoneNumber = (text) => { // Remove non-digits and limit to 7 digits const cleaned = text.replace(/\D/g, ''); return cleaned.slice(0, 7); }; const formatPin = (text) => { // Remove non-digits and limit to 6 digits const cleaned = text.replace(/\D/g, ''); return cleaned.slice(0, 6); }; const handlePhoneChange = (text) => { const formattedPhone = formatPhoneNumber(text); setPhoneNumber(formattedPhone); setPhoneError(''); }; const handlePinChange = (text) => { const formattedPin = formatPin(text); setPin(formattedPin); setPinError(''); }; const handleSubmit = () => { let hasErrors = false; // Validate phone number if (!phoneNumber) { setPhoneError('Phone number is required'); hasErrors = true; } else if (!validatePhoneNumber(phoneNumber)) { setPhoneError('Please enter a valid 7-digit Gambian phone number'); hasErrors = true; } // Validate PIN for certain wallets if (selectedWallet.id === 'afrmoney' || selectedWallet.id === 'zapp') { if (!pin) { setPinError('PIN is required for wallet transactions'); hasErrors = true; } else if (!validatePin(pin)) { setPinError('PIN must be 4-6 digits'); hasErrors = true; } } if (hasErrors) { return; } const walletData = { walletProvider: selectedWallet.id, phoneNumber: `+220${phoneNumber}`, pin: pin || undefined, }; // onWalletSubmit(walletData); }; const isFormValid = phoneNumber.length === 7 ? pin.length >= 4 : true; const getWalletInstructions = () => { switch (selectedWallet.id) { case 'afrmoney': return 'Enter your AfrMoney registered phone number and PIN to proceed with the payment.'; case 'zapp': return 'Enter your ZApp registered phone number and PIN to complete the transaction.'; default: return 'Enter your wallet details to proceed with the payment.'; } }; return (_jsxs(View, { style: styles.container, children: [_jsxs(View, { style: styles.header, children: [_jsx(TouchableOpacity, { onPress: () => { setCurrentStep('wallet-selection'); }, style: styles.backButton, children: _jsx(Text, { style: styles.backButtonText, children: "\u2190 Back" }) }), _jsx(Text, { style: styles.title, children: "Wallet Payment" }), _jsx(View, { style: styles.placeholder })] }), _jsxs(View, { style: styles.walletHeader, children: [_jsx(View, { style: styles.walletLogo, children: _jsx(Image, { source: { uri: selectedWallet.logo }, style: styles.walletLogo, resizeMode: "contain" }) }), _jsxs(View, { style: styles.walletInfo, children: [_jsx(Text, { style: styles.walletName, children: selectedWallet.name }), _jsx(Text, { style: styles.walletDescription, children: selectedWallet.description })] })] }), _jsx(Text, { style: styles.instructions, children: getWalletInstructions() }), error && (_jsx(View, { style: styles.errorContainer, children: _jsx(Text, { style: styles.errorText, children: error }) })), _jsxs(View, { style: styles.form, children: [_jsxs(View, { style: styles.formGroup, children: [_jsx(Text, { style: styles.label, children: "Phone Number *" }), _jsxs(View, { style: styles.phoneInputContainer, children: [_jsx(Text, { style: styles.countryCode, children: "+220" }), _jsx(TextInput, { style: [styles.phoneInput, phoneError ? styles.inputError : null], placeholder: "3711234", value: phoneNumber, onChangeText: handlePhoneChange, keyboardType: "numeric", maxLength: 7, editable: !isLoading, autoCorrect: false, autoCapitalize: "none", returnKeyType: "next", blurOnSubmit: false })] }), phoneError ? (_jsx(Text, { style: styles.fieldError, children: phoneError })) : null, _jsx(Text, { style: styles.helperText, children: "Enter your 7-digit Gambian phone number" })] }), _jsxs(View, { style: styles.formGroup, children: [_jsx(Text, { style: styles.label, children: "Wallet PIN *" }), _jsx(TextInput, { style: [styles.input, pinError ? styles.inputError : null], placeholder: "Enter your wallet PIN", value: pin, onChangeText: handlePinChange, keyboardType: "numeric", secureTextEntry: true, maxLength: 6, editable: !isLoading, autoCorrect: false, autoCapitalize: "none", returnKeyType: "done", blurOnSubmit: true }), pinError ? _jsx(Text, { style: styles.fieldError, children: pinError }) : null, _jsx(Text, { style: styles.helperText, children: "Enter your 4-6 digit wallet PIN" })] })] }), _jsx(View, { style: styles.submitSection, children: isLoading ? (_jsx(ShimmerButton, {})) : (_jsx(Button, { title: "Proceed to Payment", onPress: handleSubmit, disabled: !isFormValid, style: !isFormValid ? styles.submitButtonDisabled : styles.submitButton })) }), _jsx(View, { style: styles.securityNote, children: _jsx(Text, { style: styles.securityText, children: "\uD83D\uDD12 Your wallet details are encrypted and secure. We never store your PIN." }) })] })); }; 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, }, walletHeader: { flexDirection: 'row', alignItems: 'center', backgroundColor: '#f8fafc', borderRadius: 12, padding: 16, marginBottom: 20, borderWidth: 1, borderColor: '#e2e8f0', }, walletLogo: { width: 48, height: 48, backgroundColor: '#ffffff', borderRadius: 24, alignItems: 'center', justifyContent: 'center', marginRight: 16, shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.1, shadowRadius: 2, elevation: 2, }, logoText: { fontSize: 24, }, walletInfo: { flex: 1, }, walletName: { fontSize: 18, fontWeight: '600', color: '#1e293b', marginBottom: 4, }, walletDescription: { fontSize: 14, color: '#64748b', }, instructions: { fontSize: 16, color: '#475569', lineHeight: 24, marginBottom: 24, textAlign: 'center', }, errorContainer: { backgroundColor: '#fef2f2', borderColor: '#fecaca', borderWidth: 1, borderRadius: 8, padding: 12, marginBottom: 20, }, errorText: { color: '#dc2626', fontSize: 14, fontWeight: '500', }, form: { flex: 1, }, formGroup: { marginBottom: 24, }, label: { fontSize: 16, fontWeight: '600', color: '#374151', marginBottom: 8, }, phoneInputContainer: { flexDirection: 'row', alignItems: 'center', borderWidth: 1, borderColor: '#d1d5db', borderRadius: 8, backgroundColor: '#ffffff', }, countryCode: { fontSize: 16, fontWeight: '600', color: '#374151', paddingLeft: 16, paddingRight: 8, borderRightWidth: 1, borderRightColor: '#d1d5db', }, phoneInput: { flex: 1, fontSize: 16, paddingVertical: 12, paddingHorizontal: 16, color: '#374151', }, input: { borderWidth: 1, borderColor: '#d1d5db', borderRadius: 8, fontSize: 16, paddingVertical: 12, paddingHorizontal: 16, backgroundColor: '#ffffff', color: '#374151', }, inputError: { borderColor: '#dc2626', backgroundColor: '#fef2f2', }, fieldError: { color: '#dc2626', fontSize: 14, marginTop: 4, fontWeight: '500', }, helperText: { color: '#6b7280', fontSize: 14, marginTop: 4, }, submitSection: { paddingVertical: 20, }, submitButton: { backgroundColor: '#3b82f6', borderRadius: 8, }, submitButtonDisabled: { backgroundColor: '#9ca3af', opacity: 0.7, }, securityNote: { backgroundColor: '#f0f9ff', borderColor: '#bae6fd', borderWidth: 1, borderRadius: 8, padding: 12, marginBottom: 20, }, securityText: { color: '#0369a1', fontSize: 14, textAlign: 'center', fontWeight: '500', }, });