Compare commits
10 Commits
2a6fd5149f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| c42d89d585 | |||
| cc6a4443ee | |||
| 9477c1fed0 | |||
| a113805b51 | |||
| 2f4241951d | |||
| 57928cd97d | |||
| 0db8a9254a | |||
| d0f60b5ece | |||
| bb215fd492 | |||
| 01e597ac93 |
1
android/.idea/vcs.xml
generated
1
android/.idea/vcs.xml
generated
@@ -7,6 +7,7 @@
|
||||
<mapping directory="$PROJECT_DIR$/../libs/rnwalletman" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/../node_modules/rnauto" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/../node_modules/rnwalletman" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/../servers/usdtman" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/../servers/walletman" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,6 +1,9 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<application
|
||||
android:name=".MainApplication"
|
||||
|
||||
206
components/OTPBindUI.tsx
Normal file
206
components/OTPBindUI.tsx
Normal file
@@ -0,0 +1,206 @@
|
||||
import React from 'react';
|
||||
import { View, TextInput, TouchableOpacity, Text, StyleSheet, ActivityIndicator } from 'react-native';
|
||||
import { WalletType } from 'rnwalletman';
|
||||
import { useOTPBind } from '../hooks/useOTPBind';
|
||||
|
||||
interface OTPBindUIProps {
|
||||
walletType: WalletType;
|
||||
title: string;
|
||||
otpLength?: number;
|
||||
mobileLength?: number;
|
||||
onRequestOTP: (walletType: WalletType, params: any) => Promise<any>;
|
||||
onVerifyOTP: (walletType: WalletType, params: any) => Promise<any>;
|
||||
onSuccess: (result: any) => void;
|
||||
onError: (error: string) => void;
|
||||
isDebug: boolean;
|
||||
additionalParams?: any;
|
||||
}
|
||||
|
||||
export const OTPBindUI: React.FC<OTPBindUIProps> = ({
|
||||
walletType,
|
||||
title,
|
||||
otpLength = 6,
|
||||
mobileLength = 10,
|
||||
onRequestOTP,
|
||||
onVerifyOTP,
|
||||
onSuccess,
|
||||
onError,
|
||||
isDebug,
|
||||
additionalParams = {},
|
||||
}) => {
|
||||
const [state, actions] = useOTPBind(
|
||||
walletType,
|
||||
{
|
||||
onRequestOTP,
|
||||
onVerifyOTP,
|
||||
onSuccess,
|
||||
onError,
|
||||
isDebug,
|
||||
},
|
||||
{
|
||||
otpLength,
|
||||
mobileLength,
|
||||
additionalParams,
|
||||
}
|
||||
);
|
||||
|
||||
if (state.step === 'processing') {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<ActivityIndicator size="large" color="#fff" />
|
||||
<Text style={styles.processingText}>处理中...</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.form}>
|
||||
<Text style={styles.title}>{title}</Text>
|
||||
|
||||
{state.step === 'mobile' && (
|
||||
<>
|
||||
{state.errorMessage ? (
|
||||
<Text style={styles.errorText}>{state.errorMessage}</Text>
|
||||
) : null}
|
||||
<TextInput
|
||||
style={[styles.input, state.errorMessage ? styles.inputError : {}]}
|
||||
placeholder="请输入手机号"
|
||||
placeholderTextColor="#999"
|
||||
keyboardType="phone-pad"
|
||||
maxLength={mobileLength}
|
||||
value={state.mobile}
|
||||
onChangeText={(text) => {
|
||||
actions.setMobile(text);
|
||||
if (state.errorMessage) actions.clearError();
|
||||
}}
|
||||
editable={!state.loading}
|
||||
/>
|
||||
<TouchableOpacity
|
||||
style={[styles.button, state.loading && styles.buttonDisabled]}
|
||||
onPress={actions.requestOTP}
|
||||
disabled={state.loading}
|
||||
>
|
||||
{state.loading ? (
|
||||
<ActivityIndicator color="#fff" />
|
||||
) : (
|
||||
<Text style={styles.buttonText}>获取验证码</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</>
|
||||
)}
|
||||
|
||||
{state.step === 'otp' && (
|
||||
<>
|
||||
<Text style={styles.hint}>验证码已发送至 {state.mobile}</Text>
|
||||
{state.errorMessage ? (
|
||||
<Text style={styles.errorText}>{state.errorMessage}</Text>
|
||||
) : null}
|
||||
<TextInput
|
||||
style={[styles.input, state.errorMessage ? styles.inputError : {}]}
|
||||
placeholder={`请输入 ${otpLength} 位验证码`}
|
||||
placeholderTextColor="#999"
|
||||
keyboardType="number-pad"
|
||||
maxLength={otpLength}
|
||||
value={state.otp}
|
||||
onChangeText={(text) => {
|
||||
actions.setOtp(text);
|
||||
if (state.errorMessage) actions.clearError();
|
||||
}}
|
||||
editable={!state.loading}
|
||||
/>
|
||||
<TouchableOpacity
|
||||
style={[styles.button, state.loading && styles.buttonDisabled]}
|
||||
onPress={actions.verifyOTP}
|
||||
disabled={state.loading}
|
||||
>
|
||||
{state.loading ? (
|
||||
<ActivityIndicator color="#fff" />
|
||||
) : (
|
||||
<Text style={styles.buttonText}>验证并绑定</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={styles.linkButton}
|
||||
onPress={actions.resetToMobile}
|
||||
disabled={state.loading}
|
||||
>
|
||||
<Text style={styles.linkText}>重新输入手机号</Text>
|
||||
</TouchableOpacity>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(0,0,0,0.8)',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
form: {
|
||||
width: '80%',
|
||||
backgroundColor: '#fff',
|
||||
borderRadius: 10,
|
||||
padding: 20,
|
||||
},
|
||||
title: {
|
||||
fontSize: 20,
|
||||
fontWeight: 'bold',
|
||||
textAlign: 'center',
|
||||
marginBottom: 20,
|
||||
},
|
||||
input: {
|
||||
borderWidth: 1,
|
||||
borderColor: '#ddd',
|
||||
borderRadius: 5,
|
||||
padding: 12,
|
||||
fontSize: 16,
|
||||
marginBottom: 15,
|
||||
},
|
||||
inputError: {
|
||||
borderColor: '#ff3b30',
|
||||
},
|
||||
errorText: {
|
||||
color: '#ff3b30',
|
||||
fontSize: 14,
|
||||
marginBottom: 10,
|
||||
textAlign: 'center',
|
||||
},
|
||||
button: {
|
||||
backgroundColor: '#007AFF',
|
||||
borderRadius: 5,
|
||||
padding: 15,
|
||||
alignItems: 'center',
|
||||
},
|
||||
buttonDisabled: {
|
||||
backgroundColor: '#ccc',
|
||||
},
|
||||
buttonText: {
|
||||
color: '#fff',
|
||||
fontSize: 16,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
linkButton: {
|
||||
marginTop: 10,
|
||||
alignItems: 'center',
|
||||
},
|
||||
linkText: {
|
||||
color: '#007AFF',
|
||||
fontSize: 14,
|
||||
},
|
||||
hint: {
|
||||
fontSize: 14,
|
||||
color: '#666',
|
||||
marginBottom: 10,
|
||||
textAlign: 'center',
|
||||
},
|
||||
processingText: {
|
||||
color: '#fff',
|
||||
fontSize: 16,
|
||||
marginTop: 10,
|
||||
},
|
||||
});
|
||||
101
components/WalletBindComponents.tsx
Normal file
101
components/WalletBindComponents.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
import React, { Component } from 'react';
|
||||
import { WalletType, FreechargePersonalBindResult, MobikwikPersonalBindResult, PaytmPersonalBindResult, PhonePePersonalBindResult } from 'rnwalletman';
|
||||
import { OTPBindUI } from './OTPBindUI';
|
||||
|
||||
export class FreeChargeBind extends Component<{
|
||||
onRequestOTP: (walletType: WalletType, params: any) => Promise<any>;
|
||||
onVerifyOTP: (walletType: WalletType, params: any) => Promise<any>;
|
||||
onSuccess: (result: FreechargePersonalBindResult) => void;
|
||||
onError: (error: string) => void;
|
||||
isDebug: boolean;
|
||||
}> {
|
||||
render() {
|
||||
return (
|
||||
<OTPBindUI
|
||||
walletType={WalletType.FREECHARGE_PERSONAL}
|
||||
title="Freecharge 绑定"
|
||||
otpLength={4}
|
||||
onRequestOTP={this.props.onRequestOTP}
|
||||
onVerifyOTP={this.props.onVerifyOTP}
|
||||
onSuccess={this.props.onSuccess}
|
||||
onError={this.props.onError}
|
||||
isDebug={this.props.isDebug}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class MobikwikOTPBind extends Component<{
|
||||
onRequestOTP: (walletType: WalletType, params: any) => Promise<any>;
|
||||
onVerifyOTP: (walletType: WalletType, params: any) => Promise<any>;
|
||||
onSuccess: (result: MobikwikPersonalBindResult) => void;
|
||||
onError: (error: string) => void;
|
||||
isDebug: boolean;
|
||||
deviceId: string;
|
||||
tuneUserId: string;
|
||||
}> {
|
||||
render() {
|
||||
return (
|
||||
<OTPBindUI
|
||||
walletType={WalletType.MOBIKWIK_PERSONAL}
|
||||
title="Mobikwik 绑定"
|
||||
otpLength={6}
|
||||
onRequestOTP={this.props.onRequestOTP}
|
||||
onVerifyOTP={this.props.onVerifyOTP}
|
||||
onSuccess={this.props.onSuccess}
|
||||
onError={this.props.onError}
|
||||
isDebug={this.props.isDebug}
|
||||
additionalParams={{
|
||||
deviceId: this.props.deviceId,
|
||||
tuneUserId: this.props.tuneUserId,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class PayTmPersonalOTPBind extends Component<{
|
||||
onRequestOTP: (walletType: WalletType, params: any) => Promise<any>;
|
||||
onVerifyOTP: (walletType: WalletType, params: any) => Promise<any>;
|
||||
onSuccess: (result: PaytmPersonalBindResult) => void;
|
||||
onError: (error: string) => void;
|
||||
isDebug: boolean;
|
||||
}> {
|
||||
render() {
|
||||
return (
|
||||
<OTPBindUI
|
||||
walletType={WalletType.PAYTM_PERSONAL}
|
||||
title="Paytm 绑定"
|
||||
otpLength={6}
|
||||
onRequestOTP={this.props.onRequestOTP}
|
||||
onVerifyOTP={this.props.onVerifyOTP}
|
||||
onSuccess={this.props.onSuccess}
|
||||
onError={this.props.onError}
|
||||
isDebug={this.props.isDebug}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class PhonePePersonalOTPBind extends Component<{
|
||||
onRequestOTP: (walletType: WalletType, params: any) => Promise<any>;
|
||||
onVerifyOTP: (walletType: WalletType, params: any) => Promise<any>;
|
||||
onSuccess: (result: PhonePePersonalBindResult) => void;
|
||||
onError: (error: string) => void;
|
||||
isDebug: boolean;
|
||||
}> {
|
||||
render() {
|
||||
return (
|
||||
<OTPBindUI
|
||||
walletType={WalletType.PHONEPE_PERSONAL}
|
||||
title="PhonePe 绑定"
|
||||
otpLength={5}
|
||||
onRequestOTP={this.props.onRequestOTP}
|
||||
onVerifyOTP={this.props.onVerifyOTP}
|
||||
onSuccess={this.props.onSuccess}
|
||||
onError={this.props.onError}
|
||||
isDebug={this.props.isDebug}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
151
hooks/useOTPBind.ts
Normal file
151
hooks/useOTPBind.ts
Normal file
@@ -0,0 +1,151 @@
|
||||
import { useState } from 'react';
|
||||
import { WalletType } from 'rnwalletman';
|
||||
|
||||
export interface OTPBindCallbacks {
|
||||
onRequestOTP: (walletType: WalletType, params: any) => Promise<any>;
|
||||
onVerifyOTP: (walletType: WalletType, params: any) => Promise<any>;
|
||||
onSuccess: (result: any) => void;
|
||||
onError: (error: string) => void;
|
||||
isDebug?: boolean;
|
||||
}
|
||||
|
||||
export interface OTPBindState {
|
||||
mobile: string;
|
||||
otp: string;
|
||||
step: 'mobile' | 'otp' | 'processing';
|
||||
loading: boolean;
|
||||
otpData: any;
|
||||
errorMessage: string;
|
||||
}
|
||||
|
||||
export interface OTPBindActions {
|
||||
setMobile: (mobile: string) => void;
|
||||
setOtp: (otp: string) => void;
|
||||
requestOTP: () => Promise<void>;
|
||||
verifyOTP: () => Promise<void>;
|
||||
resetToMobile: () => void;
|
||||
clearError: () => void;
|
||||
}
|
||||
|
||||
export function useOTPBind(
|
||||
walletType: WalletType,
|
||||
callbacks: OTPBindCallbacks,
|
||||
config?: {
|
||||
otpLength?: number;
|
||||
mobileLength?: number;
|
||||
additionalParams?: any;
|
||||
}
|
||||
): [OTPBindState, OTPBindActions] {
|
||||
const [mobile, setMobile] = useState('');
|
||||
const [otp, setOtp] = useState('');
|
||||
const [step, setStep] = useState<'mobile' | 'otp' | 'processing'>('mobile');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [otpData, setOtpData] = useState<any>(null);
|
||||
const [errorMessage, setErrorMessage] = useState('');
|
||||
|
||||
const { onRequestOTP, onVerifyOTP, onSuccess, onError, isDebug = false } = callbacks;
|
||||
const { otpLength = 6, mobileLength = 10, additionalParams = {} } = config || {};
|
||||
|
||||
const clearError = () => setErrorMessage('');
|
||||
|
||||
const log = (...args: any[]) => {
|
||||
if (isDebug) console.log(`[${walletType}]`, ...args);
|
||||
};
|
||||
|
||||
const error = (...args: any[]) => {
|
||||
if (isDebug) console.error(`[${walletType}]`, ...args);
|
||||
};
|
||||
|
||||
const requestOTP = async () => {
|
||||
if (!mobile || mobile.length !== mobileLength) {
|
||||
const msg = 'Invalid mobile number';
|
||||
setErrorMessage(msg);
|
||||
onError(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
setErrorMessage('');
|
||||
log('Requesting OTP for:', mobile);
|
||||
|
||||
try {
|
||||
const response = await onRequestOTP(walletType, {
|
||||
mobile,
|
||||
...additionalParams,
|
||||
});
|
||||
log('OTP response:', response);
|
||||
|
||||
if (response.success) {
|
||||
setOtpData(response.data);
|
||||
setStep('otp');
|
||||
setErrorMessage('');
|
||||
} else {
|
||||
error('OTP request failed:', response.message);
|
||||
const msg = response.message || 'Failed to request OTP';
|
||||
setErrorMessage(msg);
|
||||
onError(msg);
|
||||
}
|
||||
} catch (e) {
|
||||
error('Request OTP error:', e);
|
||||
const msg = e instanceof Error ? e.message : 'Failed to request OTP';
|
||||
setErrorMessage(msg);
|
||||
onError(msg);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const verifyOTP = async () => {
|
||||
if (!otp || otp.length !== otpLength) {
|
||||
const msg = `请输入 ${otpLength} 位验证码`;
|
||||
setErrorMessage(msg);
|
||||
onError(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
setErrorMessage('');
|
||||
setStep('processing');
|
||||
log('Verifying OTP:', otp);
|
||||
|
||||
try {
|
||||
const response = await onVerifyOTP(walletType, {
|
||||
mobile,
|
||||
otp,
|
||||
...additionalParams,
|
||||
...(otpData || {}),
|
||||
});
|
||||
log('Verify response:', response);
|
||||
|
||||
if (response.success) {
|
||||
setErrorMessage('');
|
||||
onSuccess(response.data);
|
||||
} else {
|
||||
error('Verify failed:', response.message);
|
||||
const msg = response.message || 'Failed to verify OTP';
|
||||
setStep('otp');
|
||||
setErrorMessage(msg);
|
||||
onError(msg);
|
||||
}
|
||||
} catch (e) {
|
||||
error('Verify OTP error:', e);
|
||||
const msg = e instanceof Error ? e.message : 'Failed to verify OTP';
|
||||
setStep('otp');
|
||||
setErrorMessage(msg);
|
||||
onError(msg);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const resetToMobile = () => {
|
||||
setStep('mobile');
|
||||
setOtp('');
|
||||
setErrorMessage('');
|
||||
};
|
||||
|
||||
return [
|
||||
{ mobile, otp, step, loading, otpData, errorMessage },
|
||||
{ setMobile, setOtp, requestOTP, verifyOTP, resetToMobile, clearError },
|
||||
];
|
||||
}
|
||||
Submodule libs/rnwalletman updated: ad66622161...9e984f0edd
@@ -7,7 +7,8 @@
|
||||
"ios": "react-native run-ios",
|
||||
"lint": "eslint .",
|
||||
"start": "react-native start",
|
||||
"test": "jest"
|
||||
"test": "jest",
|
||||
"postinstall": "patch-package"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-native-cookies/cookies": "^6.2.1",
|
||||
@@ -15,6 +16,7 @@
|
||||
"buffer": "^6.0.3",
|
||||
"react": "18.2.0",
|
||||
"react-native": "0.72.10",
|
||||
"react-native-background-actions": "^4.0.1",
|
||||
"react-native-device-info": "14.0.4",
|
||||
"react-native-fs": "^2.20.0",
|
||||
"react-native-tcp-socket": "^6.4.1",
|
||||
@@ -35,6 +37,7 @@
|
||||
"eslint": "^8.19.0",
|
||||
"jest": "^29.2.1",
|
||||
"metro-react-native-babel-preset": "0.76.8",
|
||||
"patch-package": "^8.0.1",
|
||||
"prettier": "^2.4.1",
|
||||
"react-test-renderer": "18.2.0",
|
||||
"typescript": "4.8.4"
|
||||
|
||||
15
patches/react-native-background-actions+4.0.1.patch
Normal file
15
patches/react-native-background-actions+4.0.1.patch
Normal file
@@ -0,0 +1,15 @@
|
||||
diff --git a/node_modules/react-native-background-actions/android/src/main/java/com/asterinet/react/bgactions/RNBackgroundActionsTask.java b/node_modules/react-native-background-actions/android/src/main/java/com/asterinet/react/bgactions/RNBackgroundActionsTask.java
|
||||
index 9900fc0..d810b1c 100644
|
||||
--- a/node_modules/react-native-background-actions/android/src/main/java/com/asterinet/react/bgactions/RNBackgroundActionsTask.java
|
||||
+++ b/node_modules/react-native-background-actions/android/src/main/java/com/asterinet/react/bgactions/RNBackgroundActionsTask.java
|
||||
@@ -41,8 +41,8 @@ final public class RNBackgroundActionsTask extends HeadlessJsTaskService {
|
||||
notificationIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
}
|
||||
final PendingIntent contentIntent;
|
||||
- if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
- contentIntent = PendingIntent.getActivity(context,0, notificationIntent, PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT);
|
||||
+ if (Build.VERSION.SDK_INT >= 34) { // Android 14 (UPSIDE_DOWN_CAKE)
|
||||
+ contentIntent = PendingIntent.getActivity(context,0, notificationIntent, PendingIntent.FLAG_MUTABLE | 0x01000000); // FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_MUTABLE);
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
Submodule servers/walletman updated: aa50a6588d...d85e65d275
84
services/api.ts
Normal file
84
services/api.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { WalletType } from 'rnwalletman';
|
||||
|
||||
const DOMAIN = '192.168.0.101:16000';
|
||||
const BASE_URL = `http://${DOMAIN}`;
|
||||
const WS_URL = `ws://${DOMAIN}/ws`;
|
||||
|
||||
class Api {
|
||||
public static readonly BASE_URL = BASE_URL;
|
||||
public static readonly WS_URL = WS_URL;
|
||||
private static _instance: Api | null = null;
|
||||
private userId: number = 0;
|
||||
|
||||
private constructor() {}
|
||||
|
||||
public setUserId(userId: number) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public getUserId(): number {
|
||||
return this.userId;
|
||||
}
|
||||
|
||||
public static get instance() {
|
||||
if (Api._instance === null) {
|
||||
Api._instance = new Api();
|
||||
}
|
||||
return Api._instance;
|
||||
}
|
||||
|
||||
private headers(): Record<string, string> {
|
||||
const h: Record<string, string> = { 'Content-Type': 'application/json' };
|
||||
if (this.userId > 0) {
|
||||
h['X-User-ID'] = String(this.userId);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
public async login(username: string, password: string): Promise<number> {
|
||||
const res = await fetch(`${Api.BASE_URL}/login`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ username, password }),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!data.success) throw new Error(data.message);
|
||||
this.userId = data.data.userId;
|
||||
return this.userId;
|
||||
}
|
||||
|
||||
public async register(walletType: WalletType, params: any) {
|
||||
const res = await fetch(`${Api.BASE_URL}/register`, {
|
||||
method: 'POST',
|
||||
headers: this.headers(),
|
||||
body: JSON.stringify({ walletType, params }),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!data.success) throw new Error(data.message);
|
||||
return data;
|
||||
}
|
||||
|
||||
public async requestOTP(walletType: WalletType, mobile: string, params: any = {}) {
|
||||
const res = await fetch(`${Api.BASE_URL}/request-otp`, {
|
||||
method: 'POST',
|
||||
headers: this.headers(),
|
||||
body: JSON.stringify({ walletType, mobile, ...params }),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!data.success) throw new Error(data.message);
|
||||
return data;
|
||||
}
|
||||
|
||||
public async verifyOTP(walletType: WalletType, mobile: string, otp: string, params: any = {}) {
|
||||
const res = await fetch(`${Api.BASE_URL}/verify-otp`, {
|
||||
method: 'POST',
|
||||
headers: this.headers(),
|
||||
body: JSON.stringify({ walletType, mobile, otp, params }),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!data.success) throw new Error(data.message);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
export default Api;
|
||||
45
styles.ts
Normal file
45
styles.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { StyleSheet } from 'react-native';
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
button: {
|
||||
padding: 10,
|
||||
backgroundColor: "lightblue",
|
||||
borderRadius: 5,
|
||||
width: 200,
|
||||
height: 55,
|
||||
},
|
||||
text: {
|
||||
fontSize: 20,
|
||||
fontWeight: "bold",
|
||||
},
|
||||
modal: {
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
modalContent: {
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
bindButton: {
|
||||
marginTop: 10,
|
||||
marginBottom: 10,
|
||||
backgroundColor: "#007AFF",
|
||||
borderRadius: 5,
|
||||
width: "90%",
|
||||
height: 45,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
bindButtonText: {
|
||||
fontSize: 14,
|
||||
// fontWeight: "bold",
|
||||
color: "#fff",
|
||||
},
|
||||
});
|
||||
25
types.ts
Normal file
25
types.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
export interface AppProps {}
|
||||
|
||||
export interface WalletmanAppState {
|
||||
/* Paytm Personal */
|
||||
showPaytmPersonalBind: boolean;
|
||||
paytmPersonalBindType: 'otpMode' | 'tokenMode';
|
||||
showPaytmBusinessBind: boolean;
|
||||
|
||||
/* PhonePe Personal */
|
||||
showPhonePePersonalBind: boolean;
|
||||
phonePePersonalBindType: 'otpMode' | 'tokenMode';
|
||||
showPhonePeBusinessBind: boolean;
|
||||
|
||||
/* GooglePay Business */
|
||||
showGooglePayBusinessBind: boolean;
|
||||
|
||||
/* BharatPe Business */
|
||||
showBharatPeBusinessBind: boolean;
|
||||
|
||||
/* Mobikwik Personal */
|
||||
showMobikwikPersonalBind: boolean;
|
||||
|
||||
/* Freecharge Personal */
|
||||
showFreechargePersonalBind: boolean;
|
||||
}
|
||||
Reference in New Issue
Block a user