Files
rnpay/screens/TestScreen.tsx
T
2026-09-02 15:29:47 +08:00

375 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useEffect, useMemo, useState } from 'react';
import {
Alert,
ActivityIndicator,
Modal,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
import {
onProxyMessage,
proxySendMessage,
openPaytmPayToBank,
openPaytmPayToBank2,
openMobikwikPayToBank,
openPhonePePayToBank,
openFreechargePayToBank,
openAmazonPayPayToBank,
FreechargePersonalBind,
FreechargePersonalBindResult,
WalletType,
} from 'rnwalletman';
import Api, { loadServerDomain, saveServerDomain } from '../services/api';
const PROD_API = 'https://aa.pfgame.org';
type PayProvider = 'paytm' | 'paytm2' | 'mobikwik' | 'phonepe' | 'freecharge' | 'amazonpay';
type Payee = {
id: string;
label: string;
name: string;
account: string;
ifsc: string;
amount: string;
comment: string;
};
const PAYEES: Payee[] = [
{
id: 'harsh-psib',
label: 'Harshpreet · PSIB',
name: 'Harshpreet singh',
account: '01601000068180',
ifsc: 'PSIB0000160',
amount: '2',
comment: '66666',
},
{
id: 'harsh-cnrb',
label: 'Harshpreet · CNRB',
name: 'Harshpreet singh',
account: '110140729840',
ifsc: 'CNRB0016365',
amount: '12',
comment: 'payment',
},
{
id: 'anmol-cnrb',
label: 'Anmol · CNRB',
name: 'Anmol',
account: '5521101002938',
ifsc: 'CNRB0005521',
amount: '12',
comment: 'transfer',
},
{
id: 'fc-test',
label: 'Freecharge test · PSIB',
name: 'Test User',
account: '8284919464',
ifsc: 'PSIB0000160',
amount: '2',
comment: 'test transfer',
},
{
id: 'paytm2-demo',
label: 'Paytm deeplink demo',
name: 'Harshpreet singh',
account: '01601000068180',
ifsc: 'PSIB0000160',
amount: '3',
comment: '1234',
},
{
id: 'idbi-demo',
label: 'IDBI demo',
name: 'Test User',
account: '8910888450@nyes',
ifsc: 'IDIB000K548',
amount: '2',
comment: 'test',
},
];
const PAY_PROVIDERS: { id: PayProvider; label: string; color: string }[] = [
{ id: 'paytm', label: 'Paytm', color: '#2ecc71' },
{ id: 'paytm2', label: 'Paytm DL', color: '#27ae60' },
{ id: 'mobikwik', label: 'Mobikwik', color: '#2ecc33' },
{ id: 'phonepe', label: 'PhonePe', color: '#5a2d9c' },
{ id: 'freecharge', label: 'Freecharge', color: '#5468db' },
{ id: 'amazonpay', label: 'Amazon Pay', color: '#ff9900' },
];
async function launchPay(provider: PayProvider, payee: Payee): Promise<boolean> {
const { name, account, ifsc, amount, comment } = payee;
switch (provider) {
case 'paytm':
return openPaytmPayToBank(name, account, ifsc, amount, comment);
case 'paytm2':
return openPaytmPayToBank2(name, account, ifsc, amount, comment);
case 'mobikwik':
return openMobikwikPayToBank(name, account, ifsc, amount);
case 'phonepe':
return openPhonePePayToBank(name, account, ifsc, amount, comment);
case 'freecharge':
return openFreechargePayToBank(name, account, ifsc, amount, comment);
case 'amazonpay':
return openAmazonPayPayToBank();
default:
return false;
}
}
export default function TestScreen() {
const [selectedPayeeId, setSelectedPayeeId] = useState(PAYEES[0].id);
const [selectedProvider, setSelectedProvider] = useState<PayProvider>('freecharge');
const [showFcAuth, setShowFcAuth] = useState(false);
const [apiBaseUrl, setApiBaseUrl] = useState('');
const [fcAuthResult, setFcAuthResult] = useState<FreechargePersonalBindResult | null>(null);
const selectedPayee = useMemo(
() => PAYEES.find(p => p.id === selectedPayeeId) ?? PAYEES[0],
[selectedPayeeId],
);
useEffect(() => {
(async () => {
await saveServerDomain('aa.pfgame.org', true);
await loadServerDomain();
setApiBaseUrl(Api.BASE_URL);
})();
const sub = onProxyMessage(msg => {
if (msg.type === 'echo') {
Alert.alert('Echo Response', JSON.stringify(msg.data));
}
});
return () => sub.remove();
}, []);
const handlePay = async () => {
try {
if (selectedProvider === 'freecharge') {
console.log('[TestScreen] Freecharge account:', selectedPayee.account);
}
const ok = await launchPay(selectedProvider, selectedPayee);
if (!ok) {
Alert.alert('Pay', 'Failed to open payment app');
}
} catch (e) {
Alert.alert('Transfer Failed', String(e));
}
};
const handleEcho = () => {
proxySendMessage({
type: 'echo',
messageId: `echo_${Date.now()}`,
data: { text: `hello_${Date.now()}` },
});
};
const handleFcAuthSuccess = async (result: FreechargePersonalBindResult) => {
setFcAuthResult(result);
setShowFcAuth(false);
try {
await Api.instance.register(
WalletType.FREECHARGE_PERSONAL,
{
type: WalletType.FREECHARGE_PERSONAL,
success: true,
mobile: result.mobile,
token: result.token,
userId: result.userId || result.imsId,
extend: { appVersion: result.appVersion || '' },
},
);
Alert.alert('Register OK', 'Freecharge 钱包已注册到服务端');
} catch (e) {
Alert.alert('Register failed', String(e));
}
};
return (
<ScrollView style={styles.container} contentContainerStyle={styles.content}>
<Text style={styles.serverUrl}>Server: {apiBaseUrl || PROD_API}</Text>
<Text style={styles.sectionTitle}>收款人</Text>
{PAYEES.map(payee => {
const active = payee.id === selectedPayeeId;
return (
<TouchableOpacity
key={payee.id}
style={[styles.payeeCard, active && styles.payeeCardActive]}
onPress={() => setSelectedPayeeId(payee.id)}
>
<Text style={[styles.payeeLabel, active && styles.payeeLabelActive]}>{payee.label}</Text>
<Text style={styles.payeeMeta}>
{payee.name} · {payee.account} · {payee.ifsc}
</Text>
<Text style={styles.payeeMeta}>₹{payee.amount} · {payee.comment}</Text>
</TouchableOpacity>
);
})}
<Text style={styles.sectionTitle}>支付方式</Text>
<View style={styles.providerRow}>
{PAY_PROVIDERS.map(p => {
const active = p.id === selectedProvider;
return (
<TouchableOpacity
key={p.id}
style={[styles.providerChip, active && { backgroundColor: p.color, borderColor: p.color }]}
onPress={() => setSelectedProvider(p.id)}
>
<Text style={[styles.providerChipText, active && styles.providerChipTextActive]}>
{p.label}
</Text>
</TouchableOpacity>
);
})}
</View>
<TouchableOpacity style={[styles.btn, { backgroundColor: '#e74c3c' }]} onPress={handlePay}>
<Text style={styles.btnText}>
付款 · {PAY_PROVIDERS.find(p => p.id === selectedProvider)?.label} → {selectedPayee.label}
</Text>
</TouchableOpacity>
<Text style={styles.sectionTitle}>Freecharge Inject 授权</Text>
<TouchableOpacity
style={[styles.btn, { backgroundColor: '#5468db' }]}
onPress={() => setShowFcAuth(true)}
>
<Text style={styles.btnText}>打开 Inject 授权(官方 App WebView)</Text>
</TouchableOpacity>
{fcAuthResult ? (
<View style={styles.resultBox}>
<Text style={styles.resultTitle}>最近授权</Text>
<Text style={styles.resultText}>mobile: {fcAuthResult.mobile}</Text>
<Text style={styles.resultText}>imsId: {fcAuthResult.imsId}</Text>
<Text style={styles.resultText}>
upi: {(fcAuthResult.vpas || []).map(v => v.vpa).join(', ')}
</Text>
</View>
) : null}
<TouchableOpacity style={[styles.btn, { backgroundColor: '#3498db' }]} onPress={handleEcho}>
<Text style={styles.btnText}>Echo Test</Text>
</TouchableOpacity>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f0f0f0',
},
content: {
padding: 16,
paddingBottom: 40,
},
serverUrl: {
fontSize: 12,
color: '#1565c0',
marginBottom: 8,
fontWeight: '600',
},
sectionTitle: {
fontSize: 16,
fontWeight: '600',
color: '#333',
marginBottom: 10,
marginTop: 8,
},
payeeCard: {
backgroundColor: '#fff',
borderRadius: 10,
padding: 14,
marginBottom: 8,
borderWidth: 2,
borderColor: 'transparent',
},
payeeCardActive: {
borderColor: '#3498db',
backgroundColor: '#eef6ff',
},
payeeLabel: {
fontSize: 15,
fontWeight: '600',
color: '#333',
},
payeeLabelActive: {
color: '#1565c0',
},
payeeMeta: {
fontSize: 12,
color: '#666',
marginTop: 4,
},
providerRow: {
flexDirection: 'row',
flexWrap: 'wrap',
gap: 8,
marginBottom: 16,
},
providerChip: {
paddingHorizontal: 12,
paddingVertical: 8,
borderRadius: 20,
borderWidth: 1,
borderColor: '#ccc',
backgroundColor: '#fff',
},
providerChipText: {
fontSize: 13,
color: '#444',
fontWeight: '500',
},
providerChipTextActive: {
color: '#fff',
},
btn: {
width: '100%',
paddingVertical: 14,
borderRadius: 8,
alignItems: 'center',
marginBottom: 12,
},
btnText: {
color: '#fff',
fontSize: 15,
fontWeight: '600',
textAlign: 'center',
},
resultBox: {
backgroundColor: '#fff',
borderRadius: 10,
padding: 12,
marginBottom: 12,
},
resultTitle: {
fontWeight: '600',
marginBottom: 6,
color: '#333',
},
resultText: {
fontSize: 12,
color: '#555',
marginBottom: 2,
},
loadingBox: {
flex: 1,
backgroundColor: 'rgba(0,0,0,0.7)',
justifyContent: 'center',
alignItems: 'center',
},
modalRoot: {
flex: 1,
},
});