fix bugs
This commit is contained in:
@@ -1,5 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { View, TextInput, TouchableOpacity, Text, StyleSheet, ActivityIndicator } from 'react-native';
|
import {
|
||||||
|
View,
|
||||||
|
TextInput,
|
||||||
|
TouchableOpacity,
|
||||||
|
Text,
|
||||||
|
StyleSheet,
|
||||||
|
ActivityIndicator,
|
||||||
|
} from 'react-native';
|
||||||
import { WalletType } from 'rnwalletman';
|
import { WalletType } from 'rnwalletman';
|
||||||
import { useOTPBind } from '../hooks/useOTPBind';
|
import { useOTPBind } from '../hooks/useOTPBind';
|
||||||
|
|
||||||
@@ -30,177 +37,170 @@ export const OTPBindUI: React.FC<OTPBindUIProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const [state, actions] = useOTPBind(
|
const [state, actions] = useOTPBind(
|
||||||
walletType,
|
walletType,
|
||||||
{
|
{ onRequestOTP, onVerifyOTP, onSuccess, onError, isDebug },
|
||||||
onRequestOTP,
|
{ otpLength, mobileLength, additionalParams }
|
||||||
onVerifyOTP,
|
|
||||||
onSuccess,
|
|
||||||
onError,
|
|
||||||
isDebug,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
otpLength,
|
|
||||||
mobileLength,
|
|
||||||
additionalParams,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (state.step === 'processing') {
|
const isLoading = state.loading || state.step === 'processing';
|
||||||
return (
|
const showOtp = state.step === 'otp' || state.step === 'processing';
|
||||||
<View style={styles.container}>
|
|
||||||
<ActivityIndicator size="large" color="#fff" />
|
|
||||||
<Text style={styles.processingText}>处理中...</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.card}>
|
||||||
<View style={styles.form}>
|
<Text style={styles.title}>{title}</Text>
|
||||||
<Text style={styles.title}>{title}</Text>
|
|
||||||
|
|
||||||
{state.step === 'mobile' && (
|
{state.step === 'mobile' && (
|
||||||
<>
|
<>
|
||||||
{state.errorMessage ? (
|
{!!state.errorMessage && (
|
||||||
<Text style={styles.errorText}>{state.errorMessage}</Text>
|
<Text style={styles.errorText}>{state.errorMessage}</Text>
|
||||||
) : null}
|
)}
|
||||||
<TextInput
|
<Text style={styles.label}>手机号</Text>
|
||||||
style={[styles.input, state.errorMessage ? styles.inputError : {}]}
|
<TextInput
|
||||||
placeholder="请输入手机号"
|
style={[styles.input, !!state.errorMessage && styles.inputError]}
|
||||||
placeholderTextColor="#999"
|
placeholder={`请输入 ${mobileLength} 位手机号`}
|
||||||
keyboardType="phone-pad"
|
placeholderTextColor="#aaa"
|
||||||
maxLength={mobileLength}
|
keyboardType="phone-pad"
|
||||||
value={state.mobile}
|
maxLength={mobileLength}
|
||||||
onChangeText={(text) => {
|
value={state.mobile}
|
||||||
actions.setMobile(text);
|
onChangeText={t => {
|
||||||
if (state.errorMessage) actions.clearError();
|
actions.setMobile(t);
|
||||||
}}
|
if (state.errorMessage) actions.clearError();
|
||||||
editable={!state.loading}
|
}}
|
||||||
/>
|
editable={!isLoading}
|
||||||
<TouchableOpacity
|
/>
|
||||||
style={[styles.button, state.loading && styles.buttonDisabled]}
|
<TouchableOpacity
|
||||||
onPress={actions.requestOTP}
|
style={[styles.btn, isLoading && styles.btnDisabled]}
|
||||||
disabled={state.loading}
|
onPress={actions.requestOTP}
|
||||||
>
|
disabled={isLoading}
|
||||||
{state.loading ? (
|
activeOpacity={0.8}
|
||||||
<ActivityIndicator color="#fff" />
|
>
|
||||||
) : (
|
{isLoading ? (
|
||||||
<Text style={styles.buttonText}>获取验证码</Text>
|
<ActivityIndicator color="#fff" />
|
||||||
)}
|
) : (
|
||||||
</TouchableOpacity>
|
<Text style={styles.btnText}>获取验证码</Text>
|
||||||
</>
|
)}
|
||||||
)}
|
</TouchableOpacity>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{state.step === 'otp' && (
|
{showOtp && (
|
||||||
<>
|
<>
|
||||||
<Text style={styles.hint}>验证码已发送至 {state.mobile}</Text>
|
<Text style={styles.hint}>验证码已发送至 {state.mobile}</Text>
|
||||||
{state.errorMessage ? (
|
{!!state.errorMessage && (
|
||||||
<Text style={styles.errorText}>{state.errorMessage}</Text>
|
<Text style={styles.errorText}>{state.errorMessage}</Text>
|
||||||
) : null}
|
)}
|
||||||
<TextInput
|
<Text style={styles.label}>验证码</Text>
|
||||||
style={[styles.input, state.errorMessage ? styles.inputError : {}]}
|
<TextInput
|
||||||
placeholder={`请输入 ${otpLength} 位验证码`}
|
style={[styles.input, !!state.errorMessage && styles.inputError]}
|
||||||
placeholderTextColor="#999"
|
placeholder={`请输入 ${otpLength} 位验证码`}
|
||||||
keyboardType="number-pad"
|
placeholderTextColor="#aaa"
|
||||||
maxLength={otpLength}
|
keyboardType="number-pad"
|
||||||
value={state.otp}
|
maxLength={otpLength}
|
||||||
onChangeText={(text) => {
|
value={state.otp}
|
||||||
actions.setOtp(text);
|
onChangeText={t => {
|
||||||
if (state.errorMessage) actions.clearError();
|
actions.setOtp(t);
|
||||||
}}
|
if (state.errorMessage) actions.clearError();
|
||||||
editable={!state.loading}
|
}}
|
||||||
/>
|
editable={!isLoading}
|
||||||
<TouchableOpacity
|
/>
|
||||||
style={[styles.button, state.loading && styles.buttonDisabled]}
|
<TouchableOpacity
|
||||||
onPress={actions.verifyOTP}
|
style={[styles.btn, isLoading && styles.btnDisabled]}
|
||||||
disabled={state.loading}
|
onPress={actions.verifyOTP}
|
||||||
>
|
disabled={isLoading}
|
||||||
{state.loading ? (
|
activeOpacity={0.8}
|
||||||
<ActivityIndicator color="#fff" />
|
>
|
||||||
) : (
|
{isLoading ? (
|
||||||
<Text style={styles.buttonText}>验证并绑定</Text>
|
<ActivityIndicator color="#fff" />
|
||||||
)}
|
) : (
|
||||||
</TouchableOpacity>
|
<Text style={styles.btnText}>验证并绑定</Text>
|
||||||
<TouchableOpacity
|
)}
|
||||||
style={styles.linkButton}
|
</TouchableOpacity>
|
||||||
onPress={actions.resetToMobile}
|
<TouchableOpacity
|
||||||
disabled={state.loading}
|
style={styles.linkBtn}
|
||||||
>
|
onPress={actions.resetToMobile}
|
||||||
<Text style={styles.linkText}>重新输入手机号</Text>
|
disabled={isLoading}
|
||||||
</TouchableOpacity>
|
>
|
||||||
</>
|
<Text style={[styles.linkText, isLoading && { opacity: 0.4 }]}>
|
||||||
)}
|
重新输入手机号
|
||||||
</View>
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
card: {
|
||||||
flex: 1,
|
width: '92%',
|
||||||
backgroundColor: 'rgba(0,0,0,0.8)',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
},
|
|
||||||
form: {
|
|
||||||
width: '80%',
|
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
borderRadius: 10,
|
borderRadius: 20,
|
||||||
padding: 20,
|
padding: 28,
|
||||||
|
alignSelf: 'center',
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: 20,
|
fontSize: 22,
|
||||||
fontWeight: 'bold',
|
fontWeight: '700',
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
marginBottom: 20,
|
color: '#111',
|
||||||
|
marginBottom: 24,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
fontSize: 13,
|
||||||
|
color: '#666',
|
||||||
|
marginBottom: 6,
|
||||||
|
fontWeight: '500',
|
||||||
|
},
|
||||||
|
hint: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#555',
|
||||||
|
textAlign: 'center',
|
||||||
|
marginBottom: 18,
|
||||||
},
|
},
|
||||||
input: {
|
input: {
|
||||||
borderWidth: 1,
|
borderWidth: 1.5,
|
||||||
borderColor: '#ddd',
|
borderColor: '#e0e0e0',
|
||||||
borderRadius: 5,
|
borderRadius: 10,
|
||||||
padding: 12,
|
paddingHorizontal: 14,
|
||||||
fontSize: 16,
|
paddingVertical: 14,
|
||||||
marginBottom: 15,
|
fontSize: 17,
|
||||||
|
color: '#111',
|
||||||
|
marginBottom: 18,
|
||||||
|
backgroundColor: '#fafafa',
|
||||||
},
|
},
|
||||||
inputError: {
|
inputError: {
|
||||||
borderColor: '#ff3b30',
|
borderColor: '#ff3b30',
|
||||||
|
backgroundColor: '#fff8f7',
|
||||||
},
|
},
|
||||||
errorText: {
|
errorText: {
|
||||||
color: '#ff3b30',
|
color: '#ff3b30',
|
||||||
fontSize: 14,
|
fontSize: 13,
|
||||||
marginBottom: 10,
|
marginBottom: 12,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
|
lineHeight: 18,
|
||||||
},
|
},
|
||||||
button: {
|
btn: {
|
||||||
backgroundColor: '#007AFF',
|
backgroundColor: '#007AFF',
|
||||||
borderRadius: 5,
|
borderRadius: 12,
|
||||||
padding: 15,
|
paddingVertical: 16,
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
marginTop: 4,
|
||||||
},
|
},
|
||||||
buttonDisabled: {
|
btnDisabled: {
|
||||||
backgroundColor: '#ccc',
|
backgroundColor: '#a0c4ff',
|
||||||
},
|
},
|
||||||
buttonText: {
|
btnText: {
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
fontSize: 16,
|
fontSize: 17,
|
||||||
fontWeight: 'bold',
|
fontWeight: '600',
|
||||||
|
letterSpacing: 0.3,
|
||||||
},
|
},
|
||||||
linkButton: {
|
linkBtn: {
|
||||||
marginTop: 10,
|
marginTop: 16,
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
paddingVertical: 4,
|
||||||
},
|
},
|
||||||
linkText: {
|
linkText: {
|
||||||
color: '#007AFF',
|
color: '#007AFF',
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
},
|
},
|
||||||
hint: {
|
|
||||||
fontSize: 14,
|
|
||||||
color: '#666',
|
|
||||||
marginBottom: 10,
|
|
||||||
textAlign: 'center',
|
|
||||||
},
|
|
||||||
processingText: {
|
|
||||||
color: '#fff',
|
|
||||||
fontSize: 16,
|
|
||||||
marginTop: 10,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ function PaytmBusinessForm({ onRequestOTP, onVerifyOTP, onSuccess, onError, isDe
|
|||||||
onError: (error: string) => void;
|
onError: (error: string) => void;
|
||||||
isDebug: boolean;
|
isDebug: boolean;
|
||||||
}) {
|
}) {
|
||||||
const [step, setStep] = useState<'credentials' | 'otp' | 'processing'>('credentials');
|
const [step, setStep] = useState<'credentials' | 'otp'>('credentials');
|
||||||
const [mobile, setMobile] = useState('');
|
const [mobile, setMobile] = useState('');
|
||||||
const [otp, setOtp] = useState('');
|
const [otp, setOtp] = useState('');
|
||||||
const [sessionId, setSessionId] = useState('');
|
const [sessionId, setSessionId] = useState('');
|
||||||
@@ -153,30 +153,22 @@ function PaytmBusinessForm({ onRequestOTP, onVerifyOTP, onSuccess, onError, isDe
|
|||||||
|
|
||||||
const handleVerifyOTP = async () => {
|
const handleVerifyOTP = async () => {
|
||||||
if (!otp || otp.length !== 6) { setErrorMsg('请输入6位验证码'); return; }
|
if (!otp || otp.length !== 6) { setErrorMsg('请输入6位验证码'); return; }
|
||||||
setLoading(true); setErrorMsg(''); setStep('processing');
|
setLoading(true); setErrorMsg('');
|
||||||
try {
|
try {
|
||||||
const res = await onVerifyOTP(WalletType.PAYTM_BUSINESS, { mobile, otp, sessionId });
|
const res = await onVerifyOTP(WalletType.PAYTM_BUSINESS, { mobile, otp, sessionId });
|
||||||
log('VerifyOTP:', res);
|
log('VerifyOTP:', res);
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
onSuccess({ type: WalletType.PAYTM_BUSINESS, success: true, cookie: res.data?.cookie || '', xCsrfToken: res.data?.xCsrfToken || '', qrData: res.data?.qrData || [] });
|
onSuccess({ type: WalletType.PAYTM_BUSINESS, success: true, cookie: res.data?.cookie || '', xCsrfToken: res.data?.xCsrfToken || '', qrData: res.data?.qrData || [] });
|
||||||
} else {
|
} else {
|
||||||
const msg = res.message || 'Failed to verify OTP';
|
setErrorMsg(res.message || 'Failed to verify OTP');
|
||||||
setErrorMsg(msg); setStep('otp'); onError(msg);
|
setStep('otp');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const msg = e instanceof Error ? e.message : 'Failed to verify OTP';
|
setErrorMsg(e instanceof Error ? e.message : 'Failed to verify OTP');
|
||||||
setErrorMsg(msg); setStep('otp'); onError(msg);
|
setStep('otp');
|
||||||
} finally { setLoading(false); }
|
} finally { setLoading(false); }
|
||||||
};
|
};
|
||||||
|
|
||||||
if (step === 'processing') {
|
|
||||||
return (
|
|
||||||
<View style={ptStyles.container}>
|
|
||||||
<ActivityIndicator size="large" color="#fff" />
|
|
||||||
<Text style={ptStyles.processingText}>处理中...</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={ptStyles.container}>
|
<View style={ptStyles.container}>
|
||||||
@@ -210,17 +202,16 @@ function PaytmBusinessForm({ onRequestOTP, onVerifyOTP, onSuccess, onError, isDe
|
|||||||
|
|
||||||
const ptStyles = StyleSheet.create({
|
const ptStyles = StyleSheet.create({
|
||||||
container: { flex: 1, backgroundColor: 'rgba(0,0,0,0.8)', justifyContent: 'center', alignItems: 'center' },
|
container: { flex: 1, backgroundColor: 'rgba(0,0,0,0.8)', justifyContent: 'center', alignItems: 'center' },
|
||||||
form: { width: '80%', backgroundColor: '#fff', borderRadius: 10, padding: 20 },
|
form: { width: '92%', backgroundColor: '#fff', borderRadius: 20, padding: 28 },
|
||||||
title: { fontSize: 20, fontWeight: 'bold', textAlign: 'center', marginBottom: 20 },
|
title: { fontSize: 22, fontWeight: '700', textAlign: 'center', color: '#111', marginBottom: 24 },
|
||||||
input: { borderWidth: 1, borderColor: '#ddd', borderRadius: 5, padding: 12, fontSize: 16, marginBottom: 15 },
|
input: { borderWidth: 1.5, borderColor: '#e0e0e0', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 14, fontSize: 17, color: '#111', marginBottom: 18, backgroundColor: '#fafafa' },
|
||||||
errorText: { color: '#ff3b30', fontSize: 14, marginBottom: 10, textAlign: 'center' },
|
errorText: { color: '#ff3b30', fontSize: 13, marginBottom: 12, textAlign: 'center' },
|
||||||
button: { backgroundColor: '#007AFF', borderRadius: 5, padding: 15, alignItems: 'center' },
|
button: { backgroundColor: '#007AFF', borderRadius: 12, paddingVertical: 16, alignItems: 'center', marginTop: 4 },
|
||||||
buttonDisabled: { backgroundColor: '#ccc' },
|
buttonDisabled: { backgroundColor: '#a0c4ff' },
|
||||||
buttonText: { color: '#fff', fontSize: 16, fontWeight: 'bold' },
|
buttonText: { color: '#fff', fontSize: 17, fontWeight: '600' },
|
||||||
linkButton: { marginTop: 10, alignItems: 'center' },
|
linkButton: { marginTop: 16, alignItems: 'center' },
|
||||||
linkText: { color: '#007AFF', fontSize: 14 },
|
linkText: { color: '#007AFF', fontSize: 14 },
|
||||||
hint: { fontSize: 14, color: '#666', marginBottom: 10, textAlign: 'center' },
|
hint: { fontSize: 14, color: '#555', marginBottom: 18, textAlign: 'center' },
|
||||||
processingText: { color: '#fff', fontSize: 16, marginTop: 10 },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export class PhonePePersonalOTPBind extends Component<{
|
export class PhonePePersonalOTPBind extends Component<{
|
||||||
|
|||||||
@@ -125,14 +125,12 @@ export function useOTPBind(
|
|||||||
const msg = response.message || 'Failed to verify OTP';
|
const msg = response.message || 'Failed to verify OTP';
|
||||||
setStep('otp');
|
setStep('otp');
|
||||||
setErrorMessage(msg);
|
setErrorMessage(msg);
|
||||||
onError(msg);
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error('Verify OTP error:', e);
|
error('Verify OTP error:', e);
|
||||||
const msg = e instanceof Error ? e.message : 'Failed to verify OTP';
|
const msg = e instanceof Error ? e.message : 'Failed to verify OTP';
|
||||||
setStep('otp');
|
setStep('otp');
|
||||||
setErrorMessage(msg);
|
setErrorMessage(msg);
|
||||||
onError(msg);
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|||||||
Submodule servers/walletman updated: 9f53b50a80...ad661b4f69
Reference in New Issue
Block a user