优化
This commit is contained in:
@@ -21,6 +21,7 @@ interface OTPBindUIProps {
|
|||||||
onError: (error: string) => void;
|
onError: (error: string) => void;
|
||||||
isDebug: boolean;
|
isDebug: boolean;
|
||||||
additionalParams?: any;
|
additionalParams?: any;
|
||||||
|
initialMobile?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const OTPBindUI: React.FC<OTPBindUIProps> = ({
|
export const OTPBindUI: React.FC<OTPBindUIProps> = ({
|
||||||
@@ -34,11 +35,12 @@ export const OTPBindUI: React.FC<OTPBindUIProps> = ({
|
|||||||
onError,
|
onError,
|
||||||
isDebug,
|
isDebug,
|
||||||
additionalParams = {},
|
additionalParams = {},
|
||||||
|
initialMobile = '',
|
||||||
}) => {
|
}) => {
|
||||||
const [state, actions] = useOTPBind(
|
const [state, actions] = useOTPBind(
|
||||||
walletType,
|
walletType,
|
||||||
{ onRequestOTP, onVerifyOTP, onSuccess, onError, isDebug },
|
{ onRequestOTP, onVerifyOTP, onSuccess, onError, isDebug },
|
||||||
{ otpLength, mobileLength, additionalParams }
|
{ otpLength, mobileLength, additionalParams, initialMobile }
|
||||||
);
|
);
|
||||||
|
|
||||||
const isLoading = state.loading || state.step === 'processing';
|
const isLoading = state.loading || state.step === 'processing';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { Component, useState } from 'react';
|
import React, { Component, useState, useEffect } from 'react';
|
||||||
import { View, Text, TextInput, TouchableOpacity, StyleSheet, ActivityIndicator } from 'react-native';
|
import { View, Text, TextInput, TouchableOpacity, StyleSheet, ActivityIndicator } from 'react-native';
|
||||||
import { WalletType, FreechargePersonalBindResult, MobikwikPersonalBindResult, PaytmPersonalBindResult, PhonePePersonalBindResult, BharatPeBusinessBindResult, PaytmBusinessBindResult } from 'rnwalletman';
|
import { WalletType, FreechargePersonalBindResult, MobikwikPersonalBindResult, PaytmPersonalBindResult, PhonePePersonalBindResult, BharatPeBusinessBindResult, PaytmBusinessBindResult } from 'rnwalletman';
|
||||||
import { OTPBindUI } from './OTPBindUI';
|
import { OTPBindUI } from './OTPBindUI';
|
||||||
@@ -9,6 +9,7 @@ export class FreeChargeBind extends Component<{
|
|||||||
onSuccess: (result: FreechargePersonalBindResult) => void;
|
onSuccess: (result: FreechargePersonalBindResult) => void;
|
||||||
onError: (error: string) => void;
|
onError: (error: string) => void;
|
||||||
isDebug: boolean;
|
isDebug: boolean;
|
||||||
|
initialMobile?: string;
|
||||||
}> {
|
}> {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
@@ -21,6 +22,7 @@ export class FreeChargeBind extends Component<{
|
|||||||
onSuccess={this.props.onSuccess}
|
onSuccess={this.props.onSuccess}
|
||||||
onError={this.props.onError}
|
onError={this.props.onError}
|
||||||
isDebug={this.props.isDebug}
|
isDebug={this.props.isDebug}
|
||||||
|
initialMobile={this.props.initialMobile}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -34,6 +36,7 @@ export class MobikwikOTPBind extends Component<{
|
|||||||
isDebug: boolean;
|
isDebug: boolean;
|
||||||
deviceId: string;
|
deviceId: string;
|
||||||
tuneUserId: string;
|
tuneUserId: string;
|
||||||
|
initialMobile?: string;
|
||||||
}> {
|
}> {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
@@ -50,6 +53,7 @@ export class MobikwikOTPBind extends Component<{
|
|||||||
deviceId: this.props.deviceId,
|
deviceId: this.props.deviceId,
|
||||||
tuneUserId: this.props.tuneUserId,
|
tuneUserId: this.props.tuneUserId,
|
||||||
}}
|
}}
|
||||||
|
initialMobile={this.props.initialMobile}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -61,6 +65,7 @@ export class PayTmPersonalOTPBind extends Component<{
|
|||||||
onSuccess: (result: PaytmPersonalBindResult) => void;
|
onSuccess: (result: PaytmPersonalBindResult) => void;
|
||||||
onError: (error: string) => void;
|
onError: (error: string) => void;
|
||||||
isDebug: boolean;
|
isDebug: boolean;
|
||||||
|
initialMobile?: string;
|
||||||
}> {
|
}> {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
@@ -73,6 +78,7 @@ export class PayTmPersonalOTPBind extends Component<{
|
|||||||
onSuccess={this.props.onSuccess}
|
onSuccess={this.props.onSuccess}
|
||||||
onError={this.props.onError}
|
onError={this.props.onError}
|
||||||
isDebug={this.props.isDebug}
|
isDebug={this.props.isDebug}
|
||||||
|
initialMobile={this.props.initialMobile}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -84,6 +90,7 @@ export class BharatPeBusinessOTPBind extends Component<{
|
|||||||
onSuccess: (result: BharatPeBusinessBindResult) => void;
|
onSuccess: (result: BharatPeBusinessBindResult) => void;
|
||||||
onError: (error: string) => void;
|
onError: (error: string) => void;
|
||||||
isDebug: boolean;
|
isDebug: boolean;
|
||||||
|
initialMobile?: string;
|
||||||
}> {
|
}> {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
@@ -96,6 +103,7 @@ export class BharatPeBusinessOTPBind extends Component<{
|
|||||||
onSuccess={this.props.onSuccess}
|
onSuccess={this.props.onSuccess}
|
||||||
onError={this.props.onError}
|
onError={this.props.onError}
|
||||||
isDebug={this.props.isDebug}
|
isDebug={this.props.isDebug}
|
||||||
|
initialMobile={this.props.initialMobile}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -107,6 +115,7 @@ export class PaytmBusinessOTPBind extends Component<{
|
|||||||
onSuccess: (result: PaytmBusinessBindResult) => void;
|
onSuccess: (result: PaytmBusinessBindResult) => void;
|
||||||
onError: (error: string) => void;
|
onError: (error: string) => void;
|
||||||
isDebug: boolean;
|
isDebug: boolean;
|
||||||
|
initialMobile?: string;
|
||||||
}> {
|
}> {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
@@ -116,25 +125,31 @@ export class PaytmBusinessOTPBind extends Component<{
|
|||||||
onSuccess={this.props.onSuccess}
|
onSuccess={this.props.onSuccess}
|
||||||
onError={this.props.onError}
|
onError={this.props.onError}
|
||||||
isDebug={this.props.isDebug}
|
isDebug={this.props.isDebug}
|
||||||
|
initialMobile={this.props.initialMobile}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function PaytmBusinessForm({ onRequestOTP, onVerifyOTP, onSuccess, onError, isDebug }: {
|
function PaytmBusinessForm({ onRequestOTP, onVerifyOTP, onSuccess, onError, isDebug, initialMobile = '' }: {
|
||||||
onRequestOTP: (walletType: WalletType, params: any) => Promise<any>;
|
onRequestOTP: (walletType: WalletType, params: any) => Promise<any>;
|
||||||
onVerifyOTP: (walletType: WalletType, params: any) => Promise<any>;
|
onVerifyOTP: (walletType: WalletType, params: any) => Promise<any>;
|
||||||
onSuccess: (result: PaytmBusinessBindResult) => void;
|
onSuccess: (result: PaytmBusinessBindResult) => void;
|
||||||
onError: (error: string) => void;
|
onError: (error: string) => void;
|
||||||
isDebug: boolean;
|
isDebug: boolean;
|
||||||
|
initialMobile?: string;
|
||||||
}) {
|
}) {
|
||||||
const [step, setStep] = useState<'credentials' | 'otp'>('credentials');
|
const [step, setStep] = useState<'credentials' | 'otp'>('credentials');
|
||||||
const [mobile, setMobile] = useState('');
|
const [mobile, setMobile] = useState(initialMobile);
|
||||||
const [otp, setOtp] = useState('');
|
const [otp, setOtp] = useState('');
|
||||||
const [sessionToken, setSessionToken] = useState('');
|
const [sessionToken, setSessionToken] = useState('');
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [errorMsg, setErrorMsg] = useState('');
|
const [errorMsg, setErrorMsg] = useState('');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (initialMobile) setMobile(initialMobile);
|
||||||
|
}, [initialMobile]);
|
||||||
|
|
||||||
const log = (...args: any[]) => { if (isDebug) console.log('[PaytmBusiness]', ...args); };
|
const log = (...args: any[]) => { if (isDebug) console.log('[PaytmBusiness]', ...args); };
|
||||||
|
|
||||||
const handleRequestOTP = async () => {
|
const handleRequestOTP = async () => {
|
||||||
@@ -220,6 +235,7 @@ export class PhonePePersonalOTPBind extends Component<{
|
|||||||
onSuccess: (result: PhonePePersonalBindResult) => void;
|
onSuccess: (result: PhonePePersonalBindResult) => void;
|
||||||
onError: (error: string) => void;
|
onError: (error: string) => void;
|
||||||
isDebug: boolean;
|
isDebug: boolean;
|
||||||
|
initialMobile?: string;
|
||||||
}> {
|
}> {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
@@ -232,6 +248,7 @@ export class PhonePePersonalOTPBind extends Component<{
|
|||||||
onSuccess={this.props.onSuccess}
|
onSuccess={this.props.onSuccess}
|
||||||
onError={this.props.onError}
|
onError={this.props.onError}
|
||||||
isDebug={this.props.isDebug}
|
isDebug={this.props.isDebug}
|
||||||
|
initialMobile={this.props.initialMobile}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { WalletType } from 'rnwalletman';
|
import { WalletType } from 'rnwalletman';
|
||||||
|
|
||||||
export interface OTPBindCallbacks {
|
export interface OTPBindCallbacks {
|
||||||
@@ -34,6 +34,7 @@ export function useOTPBind(
|
|||||||
otpLength?: number;
|
otpLength?: number;
|
||||||
mobileLength?: number;
|
mobileLength?: number;
|
||||||
additionalParams?: any;
|
additionalParams?: any;
|
||||||
|
initialMobile?: string;
|
||||||
}
|
}
|
||||||
): [OTPBindState, OTPBindActions] {
|
): [OTPBindState, OTPBindActions] {
|
||||||
const [mobile, setMobile] = useState('');
|
const [mobile, setMobile] = useState('');
|
||||||
@@ -44,7 +45,11 @@ export function useOTPBind(
|
|||||||
const [errorMessage, setErrorMessage] = useState('');
|
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 = {}, initialMobile = '' } = config || {};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (initialMobile) setMobile(initialMobile);
|
||||||
|
}, [initialMobile]);
|
||||||
|
|
||||||
const clearError = () => setErrorMessage('');
|
const clearError = () => setErrorMessage('');
|
||||||
|
|
||||||
|
|||||||
Submodule libs/rnwalletman updated: 4ef1f1fe27...9e2e07c0ed
@@ -8,6 +8,7 @@ import {
|
|||||||
Modal,
|
Modal,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
|
Switch,
|
||||||
Text,
|
Text,
|
||||||
TextInput,
|
TextInput,
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
@@ -147,6 +148,30 @@ const WALLET_TYPE_OPTIONS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
function getBindKeyForWallet(item: WalletItem): string | null {
|
||||||
|
const otp = item.otpMode === true;
|
||||||
|
switch (item.walletType) {
|
||||||
|
case 'paytm':
|
||||||
|
return otp ? 'paytm_personal_otp' : 'paytm_personal_token';
|
||||||
|
case 'phonepe':
|
||||||
|
return otp ? 'phonepe_personal_otp' : 'phonepe_personal_token';
|
||||||
|
case 'paytm business':
|
||||||
|
return 'paytm_business';
|
||||||
|
case 'phonepe business':
|
||||||
|
return 'phonepe_business';
|
||||||
|
case 'googlepay business':
|
||||||
|
return 'googlepay_business';
|
||||||
|
case 'bharatpe business':
|
||||||
|
return 'bharatpe_business';
|
||||||
|
case 'mobikwik':
|
||||||
|
return 'mobikwik_personal';
|
||||||
|
case 'freecharge':
|
||||||
|
return otp ? 'freecharge_personal' : 'freecharge_personal_token';
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface HomeScreenState {
|
interface HomeScreenState {
|
||||||
// bind modals
|
// bind modals
|
||||||
showPaytmPersonalBind: boolean;
|
showPaytmPersonalBind: boolean;
|
||||||
@@ -177,6 +202,7 @@ interface HomeScreenState {
|
|||||||
vpaModalSelected: string;
|
vpaModalSelected: string;
|
||||||
// add wallet
|
// add wallet
|
||||||
showAddWallet: boolean;
|
showAddWallet: boolean;
|
||||||
|
bindPrefillMobile: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class HomeScreen extends Component<any, HomeScreenState> {
|
export default class HomeScreen extends Component<any, HomeScreenState> {
|
||||||
@@ -213,6 +239,7 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
vpaModalLoading: false,
|
vpaModalLoading: false,
|
||||||
vpaModalSelected: '',
|
vpaModalSelected: '',
|
||||||
showAddWallet: false,
|
showAddWallet: false,
|
||||||
|
bindPrefillMobile: '',
|
||||||
};
|
};
|
||||||
this.deviceId = DeviceInfo.getUniqueIdSync();
|
this.deviceId = DeviceInfo.getUniqueIdSync();
|
||||||
this.tuneUserId = Math.random().toString(36).substring(2, 15);
|
this.tuneUserId = Math.random().toString(36).substring(2, 15);
|
||||||
@@ -330,6 +357,27 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
toggleWalletActive = async (item: WalletItem, active: boolean) => {
|
||||||
|
try {
|
||||||
|
await Api.instance.setWalletStatus(item.id, active);
|
||||||
|
this.setState((s) => ({
|
||||||
|
wallets: s.wallets.map((w) =>
|
||||||
|
w.id === item.id ? { ...w, status: active ? 'ACTIVE' : 'INACTIVE' } : w),
|
||||||
|
}));
|
||||||
|
} catch (e) {
|
||||||
|
Alert.alert('Failed', (e as Error).message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleRebind = (item: WalletItem) => {
|
||||||
|
const key = getBindKeyForWallet(item);
|
||||||
|
if (!key) {
|
||||||
|
Alert.alert('Rebind', 'Unsupported wallet type');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.openWalletBind(key, item.phone);
|
||||||
|
};
|
||||||
|
|
||||||
// ---- bind handlers ----
|
// ---- bind handlers ----
|
||||||
|
|
||||||
/** Token 等需客户端 register 的流程(与 OTP 同 modal key 时勿用推断 map) */
|
/** Token 等需客户端 register 的流程(与 OTP 同 modal key 时勿用推断 map) */
|
||||||
@@ -360,10 +408,11 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
showPaytmPersonalBind, paytmPersonalBindType, showPhonePePersonalBind, phonePePersonalBindType,
|
showPaytmPersonalBind, paytmPersonalBindType, showPhonePePersonalBind, phonePePersonalBindType,
|
||||||
showPaytmBusinessBind, showPhonePeBusinessBind, showGooglePayBusinessBind, showBharatPeBusinessBind,
|
showPaytmBusinessBind, showPhonePeBusinessBind, showGooglePayBusinessBind, showBharatPeBusinessBind,
|
||||||
showMobikwikPersonalBind, showFreechargePersonalBind, freechargePersonalBindType,
|
showMobikwikPersonalBind, showFreechargePersonalBind, freechargePersonalBindType,
|
||||||
|
bindPrefillMobile,
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
const close = (key: keyof HomeScreenState) => () =>
|
const close = (key: keyof HomeScreenState) => () =>
|
||||||
this.setState({ [key]: false } as any);
|
this.setState({ [key]: false, bindPrefillMobile: '' } as any);
|
||||||
|
|
||||||
if (showPaytmPersonalBind && paytmPersonalBindType === 'tokenMode') {
|
if (showPaytmPersonalBind && paytmPersonalBindType === 'tokenMode') {
|
||||||
return (
|
return (
|
||||||
@@ -390,6 +439,7 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
>
|
>
|
||||||
<PayTmPersonalOTPBind
|
<PayTmPersonalOTPBind
|
||||||
isDebug
|
isDebug
|
||||||
|
initialMobile={bindPrefillMobile}
|
||||||
onRequestOTP={async (wt, p) =>
|
onRequestOTP={async (wt, p) =>
|
||||||
this.wrapOtpCall(() => Api.instance.requestOTP(wt, p.mobile, {}))}
|
this.wrapOtpCall(() => Api.instance.requestOTP(wt, p.mobile, {}))}
|
||||||
onVerifyOTP={async (wt, p) =>
|
onVerifyOTP={async (wt, p) =>
|
||||||
@@ -409,6 +459,8 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
>
|
>
|
||||||
<PhonePePersonalBind
|
<PhonePePersonalBind
|
||||||
processString="Processing..."
|
processString="Processing..."
|
||||||
|
mode={1}
|
||||||
|
userToken={Api.instance.getUserToken()}
|
||||||
isDebug
|
isDebug
|
||||||
onSuccess={this.handleBindSuccess('showPhonePePersonalBind', WalletType.PHONEPE_PERSONAL, 'PhonePe Personal bound successfully') as any}
|
onSuccess={this.handleBindSuccess('showPhonePePersonalBind', WalletType.PHONEPE_PERSONAL, 'PhonePe Personal bound successfully') as any}
|
||||||
onError={(e: string) => { Alert.alert('Bind Failed', e); close('showPhonePePersonalBind')(); }}
|
onError={(e: string) => { Alert.alert('Bind Failed', e); close('showPhonePePersonalBind')(); }}
|
||||||
@@ -425,6 +477,7 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
>
|
>
|
||||||
<PhonePePersonalOTPBind
|
<PhonePePersonalOTPBind
|
||||||
isDebug
|
isDebug
|
||||||
|
initialMobile={bindPrefillMobile}
|
||||||
onRequestOTP={async (wt, p) =>
|
onRequestOTP={async (wt, p) =>
|
||||||
this.wrapOtpCall(() => Api.instance.requestOTP(wt, p.mobile, {}))}
|
this.wrapOtpCall(() => Api.instance.requestOTP(wt, p.mobile, {}))}
|
||||||
onVerifyOTP={async (wt, p) =>
|
onVerifyOTP={async (wt, p) =>
|
||||||
@@ -444,6 +497,7 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
>
|
>
|
||||||
<PaytmBusinessOTPBind
|
<PaytmBusinessOTPBind
|
||||||
isDebug
|
isDebug
|
||||||
|
initialMobile={bindPrefillMobile}
|
||||||
onRequestOTP={async (wt, p) =>
|
onRequestOTP={async (wt, p) =>
|
||||||
this.wrapOtpCall(() => Api.instance.requestOTP(wt, p.mobile, {}))}
|
this.wrapOtpCall(() => Api.instance.requestOTP(wt, p.mobile, {}))}
|
||||||
onVerifyOTP={async (wt, p) =>
|
onVerifyOTP={async (wt, p) =>
|
||||||
@@ -550,6 +604,7 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
>
|
>
|
||||||
<BharatPeBusinessOTPBind
|
<BharatPeBusinessOTPBind
|
||||||
isDebug
|
isDebug
|
||||||
|
initialMobile={bindPrefillMobile}
|
||||||
onRequestOTP={async (wt, p) =>
|
onRequestOTP={async (wt, p) =>
|
||||||
this.wrapOtpCall(() => Api.instance.requestOTP(wt, p.mobile))}
|
this.wrapOtpCall(() => Api.instance.requestOTP(wt, p.mobile))}
|
||||||
onVerifyOTP={async (wt, p) =>
|
onVerifyOTP={async (wt, p) =>
|
||||||
@@ -571,6 +626,7 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
isDebug
|
isDebug
|
||||||
deviceId={this.deviceId}
|
deviceId={this.deviceId}
|
||||||
tuneUserId={this.tuneUserId}
|
tuneUserId={this.tuneUserId}
|
||||||
|
initialMobile={bindPrefillMobile}
|
||||||
onRequestOTP={async (wt, p) =>
|
onRequestOTP={async (wt, p) =>
|
||||||
this.wrapOtpCall(() => Api.instance.requestOTP(wt, p.mobile, { deviceId: p.deviceId, tuneUserId: p.tuneUserId }))}
|
this.wrapOtpCall(() => Api.instance.requestOTP(wt, p.mobile, { deviceId: p.deviceId, tuneUserId: p.tuneUserId }))}
|
||||||
onVerifyOTP={async (wt, p) =>
|
onVerifyOTP={async (wt, p) =>
|
||||||
@@ -606,6 +662,7 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
>
|
>
|
||||||
<FreeChargeBind
|
<FreeChargeBind
|
||||||
isDebug
|
isDebug
|
||||||
|
initialMobile={bindPrefillMobile}
|
||||||
onRequestOTP={async (wt, p) =>
|
onRequestOTP={async (wt, p) =>
|
||||||
this.wrapOtpCall(() => Api.instance.requestOTP(wt, p.mobile))}
|
this.wrapOtpCall(() => Api.instance.requestOTP(wt, p.mobile))}
|
||||||
onVerifyOTP={async (wt, p) =>
|
onVerifyOTP={async (wt, p) =>
|
||||||
@@ -619,8 +676,8 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
openWalletBind = (key: string) => {
|
openWalletBind = (key: string, prefillMobile?: string) => {
|
||||||
this.setState({ showAddWallet: false });
|
this.setState({ showAddWallet: false, bindPrefillMobile: prefillMobile ?? '' });
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'paytm_personal_otp':
|
case 'paytm_personal_otp':
|
||||||
@@ -779,28 +836,42 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
const color = WALLET_TYPE_COLORS[item.walletType] ?? '#888';
|
const color = WALLET_TYPE_COLORS[item.walletType] ?? '#888';
|
||||||
const isActive = item.status === 'ACTIVE';
|
const isActive = item.status === 'ACTIVE';
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity
|
<View style={s.walletCard}>
|
||||||
style={s.walletCard}
|
<TouchableOpacity
|
||||||
onPress={() => this.openVpaModal(item)}
|
onPress={() => this.openVpaModal(item)}
|
||||||
activeOpacity={0.8}
|
activeOpacity={0.8}
|
||||||
>
|
>
|
||||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||||
<View style={[s.walletBadge, !isActive && s.walletBadgeInactive]}>
|
<View style={[s.walletBadge, !isActive && s.walletBadgeInactive]}>
|
||||||
{WALLET_ICONS[item.walletType] ? (
|
{WALLET_ICONS[item.walletType] ? (
|
||||||
<Image source={WALLET_ICONS[item.walletType]} style={[s.walletIcon, !isActive && s.walletIconInactive]} resizeMode="contain" />
|
<Image source={WALLET_ICONS[item.walletType]} style={[s.walletIcon, !isActive && s.walletIconInactive]} resizeMode="contain" />
|
||||||
) : (
|
) : (
|
||||||
<View style={[s.walletIconFallback, { backgroundColor: isActive ? color : '#ccc' }]}>
|
<View style={[s.walletIconFallback, { backgroundColor: isActive ? color : '#ccc' }]}>
|
||||||
<Text style={s.walletBadgeText}>{item.walletType.split('_')[0]}</Text>
|
<Text style={s.walletBadgeText}>{item.walletType.split('_')[0]}</Text>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
</View>
|
||||||
|
<View style={{ flex: 1, marginLeft: 12 }}>
|
||||||
|
<Text style={s.walletPhone}>{item.phone || '—'}</Text>
|
||||||
|
<Text style={s.walletUpi} numberOfLines={1}>{item.upi || 'No UPI'}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={[s.statusDot, { backgroundColor: isActive ? '#2ecc71' : '#bbb' }]} />
|
||||||
</View>
|
</View>
|
||||||
<View style={{ flex: 1, marginLeft: 12 }}>
|
</TouchableOpacity>
|
||||||
<Text style={s.walletPhone}>{item.phone || '—'}</Text>
|
<View style={s.walletActions}>
|
||||||
<Text style={s.walletUpi} numberOfLines={1}>{item.upi || 'No UPI'}</Text>
|
{!isActive && (
|
||||||
</View>
|
<TouchableOpacity style={s.rebindBtn} onPress={() => this.handleRebind(item)}>
|
||||||
<View style={[s.statusDot, { backgroundColor: isActive ? '#2ecc71' : '#bbb' }]} />
|
<Text style={s.rebindBtnText}>Rebind</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
|
<Switch
|
||||||
|
value={isActive}
|
||||||
|
onValueChange={(v) => this.toggleWalletActive(item, v)}
|
||||||
|
trackColor={{ false: '#ddd', true: '#2ecc7180' }}
|
||||||
|
thumbColor={isActive ? '#2ecc71' : '#999'}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -990,6 +1061,27 @@ const s = StyleSheet.create({
|
|||||||
shadowRadius: 4,
|
shadowRadius: 4,
|
||||||
shadowOffset: { width: 0, height: 2 },
|
shadowOffset: { width: 0, height: 2 },
|
||||||
},
|
},
|
||||||
|
walletActions: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
marginTop: 10,
|
||||||
|
paddingTop: 10,
|
||||||
|
borderTopWidth: StyleSheet.hairlineWidth,
|
||||||
|
borderTopColor: '#eee',
|
||||||
|
},
|
||||||
|
rebindBtn: {
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
paddingVertical: 6,
|
||||||
|
borderRadius: 6,
|
||||||
|
backgroundColor: '#3498db',
|
||||||
|
marginRight: 12,
|
||||||
|
},
|
||||||
|
rebindBtnText: {
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: '600',
|
||||||
|
},
|
||||||
walletBadge: {
|
walletBadge: {
|
||||||
width: 52,
|
width: 52,
|
||||||
height: 52,
|
height: 52,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export interface WalletItem {
|
|||||||
upi?: string;
|
upi?: string;
|
||||||
phone?: string;
|
phone?: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
|
otpMode?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_DOMAIN = 'aa.pfgame.org';
|
const DEFAULT_DOMAIN = 'aa.pfgame.org';
|
||||||
@@ -54,6 +55,7 @@ class Api {
|
|||||||
|
|
||||||
private static _instance: Api | null = null;
|
private static _instance: Api | null = null;
|
||||||
private userId: number = 0;
|
private userId: number = 0;
|
||||||
|
private userToken: string = '';
|
||||||
|
|
||||||
private constructor() {}
|
private constructor() {}
|
||||||
|
|
||||||
@@ -65,6 +67,10 @@ class Api {
|
|||||||
return this.userId;
|
return this.userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getUserToken(): string {
|
||||||
|
return this.userToken;
|
||||||
|
}
|
||||||
|
|
||||||
public static get instance() {
|
public static get instance() {
|
||||||
if (Api._instance === null) {
|
if (Api._instance === null) {
|
||||||
Api._instance = new Api();
|
Api._instance = new Api();
|
||||||
@@ -90,6 +96,7 @@ class Api {
|
|||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (!data.success) throw new Error(data.message);
|
if (!data.success) throw new Error(data.message);
|
||||||
this.userId = data.data.userId;
|
this.userId = data.data.userId;
|
||||||
|
this.userToken = data.data.userToken ?? String(data.data.userId);
|
||||||
return this.userId;
|
return this.userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,6 +160,17 @@ class Api {
|
|||||||
return data.data?.vpa ?? '';
|
return data.data?.vpa ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async setWalletStatus(walletId: string, active: boolean): Promise<string> {
|
||||||
|
const res = await fetch(`${Api.BASE_URL}/wallet/set-status`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: this.headers(),
|
||||||
|
body: JSON.stringify({ walletId, active }),
|
||||||
|
});
|
||||||
|
const data = await res.json();
|
||||||
|
if (!data.success) throw new Error(data.message);
|
||||||
|
return data.data?.status ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
public async generateLink(walletId: string, amount: string): Promise<{ link: string; orderId: string }> {
|
public async generateLink(walletId: string, amount: string): Promise<{ link: string; orderId: string }> {
|
||||||
const res = await fetch(`${Api.BASE_URL}/generate-link`, {
|
const res = await fetch(`${Api.BASE_URL}/generate-link`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|||||||
Reference in New Issue
Block a user