import React, { Component, useState, useEffect } from 'react'; import { Alert, View, Text, TextInput, TouchableOpacity, StyleSheet, ActivityIndicator } from 'react-native'; import { WalletType, BindErrorCode, MobikwikPersonalBind, FreechargePersonalBindResult, MobikwikPersonalBindResult, PaytmPersonalBindResult, PhonePePersonalBindResult, PhonePeBusinessBindResult, BharatPeBusinessBindResult, PaytmBusinessBindResult, } from 'rnwalletman'; import { OTPBindUI } from './OTPBindUI'; export function alertMobikwikAidlBindError(code: string, message: string, onClose?: () => void) { let msg = message || 'Bind failed'; switch (code) { case BindErrorCode.NOT_INSTALLED: msg = 'Patched Mobikwik app not installed. Install mobikwik_ipay_2365.apk'; break; case BindErrorCode.NOT_LOGGED_IN: msg = 'Please log in to the Mobikwik app first'; break; case BindErrorCode.SERVICE_DISCONNECTED: msg = 'Mobikwik service unavailable. Open the app and try again'; break; case BindErrorCode.NO_DATA: msg = 'No login data received'; break; case BindErrorCode.BIND_ERROR: msg = 'Bind failed. Open Mobikwik manually and try again'; break; case BindErrorCode.NATIVE_MODULE_UNAVAILABLE: msg = 'Native module not available'; break; } Alert.alert('Bind Failed', msg); onClose?.(); } export class FreeChargeBind extends Component<{ onRequestOTP: (walletType: WalletType, params: any) => Promise; onVerifyOTP: (walletType: WalletType, params: any) => Promise; onSuccess: (result: FreechargePersonalBindResult) => void; onError: (error: string) => void; isDebug: boolean; initialMobile?: string; }> { render() { return ( ); } } /** Mobikwik 2365 AIDL bind */ export class MobikwikPersonalTokenBind extends Component<{ userToken: string; onSuccess: (result: MobikwikPersonalBindResult) => void; onClose?: () => void; isDebug?: boolean; }> { render() { const { userToken, onSuccess, onClose, isDebug = false } = this.props; return ( { if (!result.hashId) { Alert.alert('Bind Failed', 'Please log in to the Mobikwik app first'); return; } onSuccess(result); }} onError={(code: string, message: string) => alertMobikwikAidlBindError(code, message, onClose)} /> ); } } /** Mobikwik web OTP bind */ export class MobikwikPersonalOTPBind extends Component<{ onRequestOTP: (walletType: WalletType, params: any) => Promise; onVerifyOTP: (walletType: WalletType, params: any) => Promise; onSuccess: (result: any) => void; onError: (error: string) => void; isDebug: boolean; initialMobile?: string; }> { render() { return ( ); } } /** @deprecated Use MobikwikPersonalOTPBind */ export const MobikwikOTPBind = MobikwikPersonalOTPBind; export class PayTmPersonalOTPBind extends Component<{ onRequestOTP: (walletType: WalletType, params: any) => Promise; onVerifyOTP: (walletType: WalletType, params: any) => Promise; onSuccess: (result: PaytmPersonalBindResult) => void; onError: (error: string) => void; isDebug: boolean; initialMobile?: string; }> { render() { return ( ); } } export class BharatPeBusinessOTPBind extends Component<{ onRequestOTP: (walletType: WalletType, params: any) => Promise; onVerifyOTP: (walletType: WalletType, params: any) => Promise; onSuccess: (result: BharatPeBusinessBindResult) => void; onError: (error: string) => void; isDebug: boolean; initialMobile?: string; }> { render() { return ( ); } } export class PaytmBusinessOTPBind extends Component<{ onRequestOTP: (walletType: WalletType, params: any) => Promise; onVerifyOTP: (walletType: WalletType, params: any) => Promise; onSuccess: (result: PaytmBusinessBindResult) => void; onError: (error: string) => void; isDebug: boolean; initialMobile?: string; }> { render() { return ( ); } } function PaytmBusinessForm({ onRequestOTP, onVerifyOTP, onSuccess, onError, isDebug, initialMobile = '' }: { onRequestOTP: (walletType: WalletType, params: any) => Promise; onVerifyOTP: (walletType: WalletType, params: any) => Promise; onSuccess: (result: PaytmBusinessBindResult) => void; onError: (error: string) => void; isDebug: boolean; initialMobile?: string; }) { const [step, setStep] = useState<'credentials' | 'otp'>('credentials'); const [mobile, setMobile] = useState(initialMobile); const [otp, setOtp] = useState(''); const [sessionToken, setSessionToken] = useState(''); const [loading, setLoading] = useState(false); const [errorMsg, setErrorMsg] = useState(''); useEffect(() => { if (initialMobile) setMobile(initialMobile); }, [initialMobile]); const log = (...args: any[]) => { if (isDebug) console.log('[PaytmBusiness]', ...args); }; const handleRequestOTP = async () => { if (!mobile || mobile.length !== 10) { setErrorMsg('Please enter a 10-digit mobile number'); return; } setLoading(true); setErrorMsg(''); try { const res = await onRequestOTP(WalletType.PAYTM_BUSINESS, { mobile }); log('RequestOTP:', res); if (res.success) { setSessionToken(res.data?.sessionToken || ''); setStep('otp'); } else { const msg = res.message || 'Failed to send OTP'; setErrorMsg(msg); onError(msg); } } catch (e) { const msg = e instanceof Error ? e.message : 'Failed to send OTP'; setErrorMsg(msg); onError(msg); } finally { setLoading(false); } }; const handleVerifyOTP = async () => { if (!otp || otp.length !== 6) { setErrorMsg('Please enter the 6-digit verification code'); return; } setLoading(true); setErrorMsg(''); try { const res = await onVerifyOTP(WalletType.PAYTM_BUSINESS, { mobile, otp, sessionToken }); log('VerifyOTP:', res); if (res.success) { onSuccess({ type: WalletType.PAYTM_BUSINESS, success: true, cookie: res.data?.cookie || '', xCsrfToken: res.data?.xCsrfToken || '', qrData: res.data?.qrData || [] }); } else { setErrorMsg(res.message || 'Failed to verify OTP'); setStep('otp'); } } catch (e) { setErrorMsg(e instanceof Error ? e.message : 'Failed to verify OTP'); setStep('otp'); } finally { setLoading(false); } }; return ( Bind Paytm Business {errorMsg ? {errorMsg} : null} {step === 'credentials' && ( <> { setMobile(t); setErrorMsg(''); }} editable={!loading} /> {loading ? : Send OTP} )} {step === 'otp' && ( <> OTP sent to {mobile} { setOtp(t); setErrorMsg(''); }} editable={!loading} /> {loading ? : Verify & Bind} setStep('credentials')} disabled={loading}> Change mobile number )} ); } const ptStyles = StyleSheet.create({ container: { flex: 1, backgroundColor: 'rgba(0,0,0,0.8)', justifyContent: 'center', alignItems: 'center' }, form: { width: '92%', backgroundColor: '#fff', borderRadius: 20, padding: 28 }, title: { fontSize: 22, fontWeight: '700', textAlign: 'center', color: '#111', marginBottom: 24 }, input: { borderWidth: 1.5, borderColor: '#e0e0e0', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 14, fontSize: 17, color: '#111', marginBottom: 18, backgroundColor: '#fafafa' }, errorText: { color: '#ff3b30', fontSize: 13, marginBottom: 12, textAlign: 'center' }, button: { backgroundColor: '#007AFF', borderRadius: 12, paddingVertical: 16, alignItems: 'center', marginTop: 4 }, buttonDisabled: { backgroundColor: '#a0c4ff' }, buttonText: { color: '#fff', fontSize: 17, fontWeight: '600' }, linkButton: { marginTop: 16, alignItems: 'center' }, linkText: { color: '#007AFF', fontSize: 14 }, hint: { fontSize: 14, color: '#555', marginBottom: 18, textAlign: 'center' }, }); export class PhonePeBusinessOTPBind extends Component<{ onRequestOTP: (walletType: WalletType, params: any) => Promise; onVerifyOTP: (walletType: WalletType, params: any) => Promise; onSuccess: (result: PhonePeBusinessBindResult) => void; onError: (error: string) => void; isDebug: boolean; initialMobile?: string; }> { render() { return ( ); } } export class PhonePePersonalOTPBind extends Component<{ onRequestOTP: (walletType: WalletType, params: any) => Promise; onVerifyOTP: (walletType: WalletType, params: any) => Promise; onSuccess: (result: PhonePePersonalBindResult) => void; onError: (error: string) => void; isDebug: boolean; initialMobile?: string; }> { render() { return ( ); } } export class AmazonPayOTPBind extends Component<{ onRequestOTP: (walletType: WalletType, params: any) => Promise; onVerifyOTP: (walletType: WalletType, params: any) => Promise; onSuccess: (result: any) => void; onError: (error: string) => void; isDebug: boolean; initialMobile?: string; }> { render() { return ( ); } }