fix ui
This commit is contained in:
34
App.tsx
34
App.tsx
@@ -71,6 +71,16 @@ export default class App extends Component<AppProps, WalletmanAppState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
|
// 先登录获取 userId
|
||||||
|
try {
|
||||||
|
const userId = await Api.instance.login('test123', '123456');
|
||||||
|
console.log('[登录成功] userId:', userId);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[登录失败]', error);
|
||||||
|
Alert.alert('登录失败', String(error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await this.setupPermissions();
|
await this.setupPermissions();
|
||||||
await this.initProxyClient();
|
await this.initProxyClient();
|
||||||
this.appStateSubscription = AppState.addEventListener('change', this.handleAppStateChange);
|
this.appStateSubscription = AppState.addEventListener('change', this.handleAppStateChange);
|
||||||
@@ -107,18 +117,20 @@ export default class App extends Component<AppProps, WalletmanAppState> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
onNotificationMessage((msg: NotificationMessage) => {
|
onNotificationMessage((msg: NotificationMessage) => {
|
||||||
console.log('[Notification]', msg.packageName, msg.title, msg.text);
|
// console.log('[Notification]', msg.packageName, msg.title, msg.text);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async initProxyClient() {
|
async initProxyClient() {
|
||||||
try {
|
try {
|
||||||
this.clientId = DeviceInfo.getUniqueIdSync();
|
this.clientId = DeviceInfo.getUniqueIdSync();
|
||||||
console.log('[Proxy] 初始化客户端:', this.clientId);
|
const userId = Api.instance.getUserId();
|
||||||
|
console.log('[Proxy] 初始化客户端:', this.clientId, 'userId:', userId);
|
||||||
|
|
||||||
await proxyManager.start({
|
await proxyManager.start({
|
||||||
wsUrl: 'ws://192.168.1.117:16001/ws',
|
wsUrl: 'ws://192.168.1.117:16001/ws',
|
||||||
clientId: this.clientId || '',
|
clientId: this.clientId || '',
|
||||||
userId: 1,
|
userId: userId,
|
||||||
debug: true,
|
debug: true,
|
||||||
heartbeatInterval: 10000,
|
heartbeatInterval: 10000,
|
||||||
reconnectInterval: 5000,
|
reconnectInterval: 5000,
|
||||||
@@ -130,13 +142,12 @@ export default class App extends Component<AppProps, WalletmanAppState> {
|
|||||||
console.log('[Proxy] 客户端已断开');
|
console.log('[Proxy] 客户端已断开');
|
||||||
},
|
},
|
||||||
onError: (error: string) => {
|
onError: (error: string) => {
|
||||||
console.error('[Proxy] 错误:', error);
|
console.warn('[Proxy] 错误:', error);
|
||||||
},
|
},
|
||||||
onRegister: (ws: WebSocket, clientId: string, userId: number) => {
|
onRegister: (ws: WebSocket, clientId: string, userId: number) => {
|
||||||
console.log('[Proxy] 客户端已注册:', clientId, userId);
|
console.log('[Proxy] 客户端已注册:', clientId, userId);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
console.log('[Proxy] 客户端已连接');
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[Proxy] 初始化失败:', error);
|
console.error('[Proxy] 初始化失败:', error);
|
||||||
}
|
}
|
||||||
@@ -164,11 +175,13 @@ export default class App extends Component<AppProps, WalletmanAppState> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Paytm Personal
|
// Paytm Personal
|
||||||
handleUploadPaytmPersonal = async (result: PaytmPersonalBindResult) => {
|
handleUploadPaytmPersonalToken = async (result: PaytmPersonalBindResult) => {
|
||||||
try {
|
try {
|
||||||
console.log(result);
|
console.log(result);
|
||||||
await Api.instance.register(WalletType.PAYTM_PERSONAL, result);
|
await Api.instance.register(WalletType.PAYTM_PERSONAL, result);
|
||||||
this.setState({ showPaytmPersonalBind: false });
|
this.setState({ showPaytmPersonalBind: false });
|
||||||
|
console.log('绑定成功', 'Paytm Personal Token 绑定成功');
|
||||||
|
Alert.alert('绑定成功', 'Paytm Personal Token 绑定成功');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Alert.alert('绑定失败', (error as Error).message);
|
Alert.alert('绑定失败', (error as Error).message);
|
||||||
this.setState({ showPaytmPersonalBind: false });
|
this.setState({ showPaytmPersonalBind: false });
|
||||||
@@ -265,7 +278,7 @@ export default class App extends Component<AppProps, WalletmanAppState> {
|
|||||||
<PaytmPersonalBind
|
<PaytmPersonalBind
|
||||||
processString="Processing..."
|
processString="Processing..."
|
||||||
isDebug={true}
|
isDebug={true}
|
||||||
onSuccess={this.handleUploadPaytmPersonal}
|
onSuccess={this.handleUploadPaytmPersonalToken}
|
||||||
onError={(error: string) => {
|
onError={(error: string) => {
|
||||||
Alert.alert('绑定失败', error);
|
Alert.alert('绑定失败', error);
|
||||||
this.setState({ showPaytmPersonalBind: false });
|
this.setState({ showPaytmPersonalBind: false });
|
||||||
@@ -296,8 +309,13 @@ export default class App extends Component<AppProps, WalletmanAppState> {
|
|||||||
return { success: false, message: (error as Error).message };
|
return { success: false, message: (error as Error).message };
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onSuccess={this.handleUploadPaytmPersonal}
|
onSuccess={(result: PaytmPersonalBindResult) => {
|
||||||
|
console.log('[PaytmPersonal] OTP 绑定成功:', result);
|
||||||
|
Alert.alert('绑定成功', 'Paytm Personal OTP 绑定成功');
|
||||||
|
this.setState({ showPaytmPersonalBind: false });
|
||||||
|
}}
|
||||||
onError={(error: string) => {
|
onError={(error: string) => {
|
||||||
|
console.log('[PaytmPersonal] OTP 绑定失败:', error);
|
||||||
Alert.alert('绑定失败', error);
|
Alert.alert('绑定失败', error);
|
||||||
this.setState({ showPaytmPersonalBind: false });
|
this.setState({ showPaytmPersonalBind: false });
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -60,14 +60,20 @@ export const OTPBindUI: React.FC<OTPBindUIProps> = ({
|
|||||||
|
|
||||||
{state.step === 'mobile' && (
|
{state.step === 'mobile' && (
|
||||||
<>
|
<>
|
||||||
|
{state.errorMessage ? (
|
||||||
|
<Text style={styles.errorText}>{state.errorMessage}</Text>
|
||||||
|
) : null}
|
||||||
<TextInput
|
<TextInput
|
||||||
style={styles.input}
|
style={[styles.input, state.errorMessage ? styles.inputError : {}]}
|
||||||
placeholder="请输入手机号"
|
placeholder="请输入手机号"
|
||||||
placeholderTextColor="#999"
|
placeholderTextColor="#999"
|
||||||
keyboardType="phone-pad"
|
keyboardType="phone-pad"
|
||||||
maxLength={mobileLength}
|
maxLength={mobileLength}
|
||||||
value={state.mobile}
|
value={state.mobile}
|
||||||
onChangeText={actions.setMobile}
|
onChangeText={(text) => {
|
||||||
|
actions.setMobile(text);
|
||||||
|
if (state.errorMessage) actions.clearError();
|
||||||
|
}}
|
||||||
editable={!state.loading}
|
editable={!state.loading}
|
||||||
/>
|
/>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
@@ -87,14 +93,20 @@ export const OTPBindUI: React.FC<OTPBindUIProps> = ({
|
|||||||
{state.step === 'otp' && (
|
{state.step === 'otp' && (
|
||||||
<>
|
<>
|
||||||
<Text style={styles.hint}>验证码已发送至 {state.mobile}</Text>
|
<Text style={styles.hint}>验证码已发送至 {state.mobile}</Text>
|
||||||
|
{state.errorMessage ? (
|
||||||
|
<Text style={styles.errorText}>{state.errorMessage}</Text>
|
||||||
|
) : null}
|
||||||
<TextInput
|
<TextInput
|
||||||
style={styles.input}
|
style={[styles.input, state.errorMessage ? styles.inputError : {}]}
|
||||||
placeholder={`请输入 ${otpLength} 位验证码`}
|
placeholder={`请输入 ${otpLength} 位验证码`}
|
||||||
placeholderTextColor="#999"
|
placeholderTextColor="#999"
|
||||||
keyboardType="number-pad"
|
keyboardType="number-pad"
|
||||||
maxLength={otpLength}
|
maxLength={otpLength}
|
||||||
value={state.otp}
|
value={state.otp}
|
||||||
onChangeText={actions.setOtp}
|
onChangeText={(text) => {
|
||||||
|
actions.setOtp(text);
|
||||||
|
if (state.errorMessage) actions.clearError();
|
||||||
|
}}
|
||||||
editable={!state.loading}
|
editable={!state.loading}
|
||||||
/>
|
/>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
@@ -149,6 +161,15 @@ const styles = StyleSheet.create({
|
|||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
marginBottom: 15,
|
marginBottom: 15,
|
||||||
},
|
},
|
||||||
|
inputError: {
|
||||||
|
borderColor: '#ff3b30',
|
||||||
|
},
|
||||||
|
errorText: {
|
||||||
|
color: '#ff3b30',
|
||||||
|
fontSize: 14,
|
||||||
|
marginBottom: 10,
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
button: {
|
button: {
|
||||||
backgroundColor: '#007AFF',
|
backgroundColor: '#007AFF',
|
||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export class PayTmPersonalOTPBind extends Component<{
|
|||||||
<OTPBindUI
|
<OTPBindUI
|
||||||
walletType={WalletType.PAYTM_PERSONAL}
|
walletType={WalletType.PAYTM_PERSONAL}
|
||||||
title="Paytm 绑定"
|
title="Paytm 绑定"
|
||||||
otpLength={8}
|
otpLength={6}
|
||||||
onRequestOTP={this.props.onRequestOTP}
|
onRequestOTP={this.props.onRequestOTP}
|
||||||
onVerifyOTP={this.props.onVerifyOTP}
|
onVerifyOTP={this.props.onVerifyOTP}
|
||||||
onSuccess={this.props.onSuccess}
|
onSuccess={this.props.onSuccess}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export interface OTPBindState {
|
|||||||
step: 'mobile' | 'otp' | 'processing';
|
step: 'mobile' | 'otp' | 'processing';
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
otpData: any;
|
otpData: any;
|
||||||
|
errorMessage: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OTPBindActions {
|
export interface OTPBindActions {
|
||||||
@@ -23,6 +24,7 @@ export interface OTPBindActions {
|
|||||||
requestOTP: () => Promise<void>;
|
requestOTP: () => Promise<void>;
|
||||||
verifyOTP: () => Promise<void>;
|
verifyOTP: () => Promise<void>;
|
||||||
resetToMobile: () => void;
|
resetToMobile: () => void;
|
||||||
|
clearError: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useOTPBind(
|
export function useOTPBind(
|
||||||
@@ -39,10 +41,13 @@ export function useOTPBind(
|
|||||||
const [step, setStep] = useState<'mobile' | 'otp' | 'processing'>('mobile');
|
const [step, setStep] = useState<'mobile' | 'otp' | 'processing'>('mobile');
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [otpData, setOtpData] = useState<any>(null);
|
const [otpData, setOtpData] = useState<any>(null);
|
||||||
|
const [errorMessage, setErrorMessage] = useState('');
|
||||||
|
|
||||||
const { onRequestOTP, onVerifyOTP, onSuccess, onError, isDebug = false } = callbacks;
|
const { onRequestOTP, onVerifyOTP, onSuccess, onError, isDebug = false } = callbacks;
|
||||||
const { otpLength = 6, mobileLength = 10, additionalParams = {} } = config || {};
|
const { otpLength = 6, mobileLength = 10, additionalParams = {} } = config || {};
|
||||||
|
|
||||||
|
const clearError = () => setErrorMessage('');
|
||||||
|
|
||||||
const log = (...args: any[]) => {
|
const log = (...args: any[]) => {
|
||||||
if (isDebug) console.log(`[${walletType}]`, ...args);
|
if (isDebug) console.log(`[${walletType}]`, ...args);
|
||||||
};
|
};
|
||||||
@@ -53,11 +58,14 @@ export function useOTPBind(
|
|||||||
|
|
||||||
const requestOTP = async () => {
|
const requestOTP = async () => {
|
||||||
if (!mobile || mobile.length !== mobileLength) {
|
if (!mobile || mobile.length !== mobileLength) {
|
||||||
onError('Invalid mobile number');
|
const msg = 'Invalid mobile number';
|
||||||
|
setErrorMessage(msg);
|
||||||
|
onError(msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
setErrorMessage('');
|
||||||
log('Requesting OTP for:', mobile);
|
log('Requesting OTP for:', mobile);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -70,13 +78,18 @@ export function useOTPBind(
|
|||||||
if (response.success) {
|
if (response.success) {
|
||||||
setOtpData(response.data);
|
setOtpData(response.data);
|
||||||
setStep('otp');
|
setStep('otp');
|
||||||
|
setErrorMessage('');
|
||||||
} else {
|
} else {
|
||||||
error('OTP request failed:', response.message);
|
error('OTP request failed:', response.message);
|
||||||
onError(response.message || 'Failed to request OTP');
|
const msg = response.message || 'Failed to request OTP';
|
||||||
|
setErrorMessage(msg);
|
||||||
|
onError(msg);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error('Request OTP error:', e);
|
error('Request OTP error:', e);
|
||||||
onError(e instanceof Error ? e.message : 'Failed to request OTP');
|
const msg = e instanceof Error ? e.message : 'Failed to request OTP';
|
||||||
|
setErrorMessage(msg);
|
||||||
|
onError(msg);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -84,11 +97,14 @@ export function useOTPBind(
|
|||||||
|
|
||||||
const verifyOTP = async () => {
|
const verifyOTP = async () => {
|
||||||
if (!otp || otp.length !== otpLength) {
|
if (!otp || otp.length !== otpLength) {
|
||||||
onError(`Invalid OTP (expected ${otpLength} digits)`);
|
const msg = `请输入 ${otpLength} 位验证码`;
|
||||||
|
setErrorMessage(msg);
|
||||||
|
onError(msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
setErrorMessage('');
|
||||||
setStep('processing');
|
setStep('processing');
|
||||||
log('Verifying OTP:', otp);
|
log('Verifying OTP:', otp);
|
||||||
|
|
||||||
@@ -102,16 +118,21 @@ export function useOTPBind(
|
|||||||
log('Verify response:', response);
|
log('Verify response:', response);
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
|
setErrorMessage('');
|
||||||
onSuccess(response.data);
|
onSuccess(response.data);
|
||||||
} else {
|
} else {
|
||||||
error('Verify failed:', response.message);
|
error('Verify failed:', response.message);
|
||||||
|
const msg = response.message || 'Failed to verify OTP';
|
||||||
setStep('otp');
|
setStep('otp');
|
||||||
onError(response.message || 'Failed to verify OTP');
|
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';
|
||||||
setStep('otp');
|
setStep('otp');
|
||||||
onError(e instanceof Error ? e.message : 'Failed to verify OTP');
|
setErrorMessage(msg);
|
||||||
|
onError(msg);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -120,10 +141,11 @@ export function useOTPBind(
|
|||||||
const resetToMobile = () => {
|
const resetToMobile = () => {
|
||||||
setStep('mobile');
|
setStep('mobile');
|
||||||
setOtp('');
|
setOtp('');
|
||||||
|
setErrorMessage('');
|
||||||
};
|
};
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{ mobile, otp, step, loading, otpData },
|
{ mobile, otp, step, loading, otpData, errorMessage },
|
||||||
{ setMobile, setOtp, requestOTP, verifyOTP, resetToMobile },
|
{ setMobile, setOtp, requestOTP, verifyOTP, resetToMobile, clearError },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
Submodule libs/rnwalletman updated: 51280d4a12...0179dfbc68
@@ -24,7 +24,9 @@ class Api {
|
|||||||
|
|
||||||
private headers(): Record<string, string> {
|
private headers(): Record<string, string> {
|
||||||
const h: Record<string, string> = { 'Content-Type': 'application/json' };
|
const h: Record<string, string> = { 'Content-Type': 'application/json' };
|
||||||
if (this.userId) h['X-User-ID'] = String(this.userId);
|
if (this.userId > 0) {
|
||||||
|
h['X-User-ID'] = String(this.userId);
|
||||||
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,19 +28,18 @@ export const styles = StyleSheet.create({
|
|||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
},
|
},
|
||||||
bindButton: {
|
bindButton: {
|
||||||
padding: 10,
|
|
||||||
marginTop: 10,
|
marginTop: 10,
|
||||||
marginBottom: 10,
|
marginBottom: 10,
|
||||||
backgroundColor: "#007AFF",
|
backgroundColor: "#007AFF",
|
||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
width: "90%",
|
width: "90%",
|
||||||
height: 55,
|
height: 45,
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
},
|
},
|
||||||
bindButtonText: {
|
bindButtonText: {
|
||||||
fontSize: 16,
|
fontSize: 14,
|
||||||
fontWeight: "bold",
|
// fontWeight: "bold",
|
||||||
color: "#fff",
|
color: "#fff",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user