mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-04-22 10:17:54 +00:00
24d6a942f8
BREAKING: Removed multi-language support (i18n) - will be re-added later Changes: - Removed i18n system (6 language files, LanguageContext) - Expanded WalletScreen, SettingsScreen, SwapScreen with more features - Added KurdistanSun component, HEZ/PEZ token icons - Added EditProfileScreen, WalletSetupScreen - Added button e2e tests (Profile, Settings, Wallet) - Updated plan: honest assessment - 42 nav buttons with mock data - Fixed terminology: Polkadot→Pezkuwi, Substrate→Bizinikiwi Reality check: UI complete with mock data, converting to production one-by-one
1342 lines
41 KiB
TypeScript
1342 lines
41 KiB
TypeScript
import React, { useState, useEffect, useCallback } from 'react';
|
||
import {
|
||
View,
|
||
Text,
|
||
TouchableOpacity,
|
||
StyleSheet,
|
||
SafeAreaView,
|
||
ScrollView,
|
||
StatusBar,
|
||
Modal,
|
||
TextInput,
|
||
Alert,
|
||
ActivityIndicator,
|
||
RefreshControl,
|
||
Image,
|
||
Platform,
|
||
Clipboard,
|
||
Share,
|
||
} from 'react-native';
|
||
import { LinearGradient } from 'expo-linear-gradient';
|
||
import { useNavigation } from '@react-navigation/native';
|
||
import QRCode from 'react-native-qrcode-svg';
|
||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||
import * as SecureStore from 'expo-secure-store';
|
||
import { KurdistanColors } from '../theme/colors';
|
||
import { usePezkuwi, NetworkType, NETWORKS } from '../contexts/PezkuwiContext';
|
||
import { AddTokenModal } from '../components/wallet/AddTokenModal';
|
||
import { HezTokenLogo, PezTokenLogo } from '../components/icons';
|
||
|
||
// Secure storage helper - same as in PezkuwiContext
|
||
const secureStorage = {
|
||
getItem: async (key: string): Promise<string | null> => {
|
||
if (Platform.OS === 'web') {
|
||
return await AsyncStorage.getItem(key);
|
||
} else {
|
||
return await SecureStore.getItemAsync(key);
|
||
}
|
||
},
|
||
};
|
||
|
||
// Cross-platform alert helper
|
||
const showAlert = (title: string, message: string, buttons?: Array<{text: string; onPress?: () => void; style?: string}>) => {
|
||
if (Platform.OS === 'web') {
|
||
if (buttons && buttons.length > 1) {
|
||
const result = window.confirm(`${title}\n\n${message}`);
|
||
if (result && buttons[1]?.onPress) {
|
||
buttons[1].onPress();
|
||
} else if (!result && buttons[0]?.onPress) {
|
||
buttons[0].onPress();
|
||
}
|
||
} else {
|
||
window.alert(`${title}\n\n${message}`);
|
||
if (buttons?.[0]?.onPress) buttons[0].onPress();
|
||
}
|
||
} else {
|
||
showAlert(title, message, buttons as any);
|
||
}
|
||
};
|
||
|
||
// Token Images - From shared/images
|
||
const hezLogo = require('../../../shared/images/hez_logo.png');
|
||
const pezLogo = require('../../../shared/images/pez_logo.jpg');
|
||
const usdtLogo = require('../../../shared/images/USDT(hez)logo.png');
|
||
const dotLogo = require('../../../shared/images/dot.png');
|
||
const btcLogo = require('../../../shared/images/bitcoin.png');
|
||
const ethLogo = require('../../../shared/images/etherium.png');
|
||
const bnbLogo = require('../../../shared/images/BNB_logo.png');
|
||
const adaLogo = require('../../../shared/images/ADAlogo.png');
|
||
|
||
interface Token {
|
||
symbol: string;
|
||
name: string;
|
||
balance: string;
|
||
value: string;
|
||
change: string;
|
||
logo: any; // Image source
|
||
assetId?: number;
|
||
isLive: boolean;
|
||
}
|
||
|
||
interface Transaction {
|
||
hash: string;
|
||
method: string;
|
||
section: string;
|
||
from: string;
|
||
to?: string;
|
||
amount?: string;
|
||
blockNumber: number;
|
||
timestamp?: number;
|
||
isIncoming: boolean;
|
||
}
|
||
|
||
const WalletScreen: React.FC = () => {
|
||
const navigation = useNavigation<any>();
|
||
const {
|
||
api,
|
||
isApiReady,
|
||
accounts,
|
||
selectedAccount,
|
||
setSelectedAccount,
|
||
connectWallet,
|
||
disconnectWallet,
|
||
createWallet,
|
||
deleteWallet,
|
||
getKeyPair,
|
||
currentNetwork,
|
||
switchNetwork,
|
||
error: pezkuwiError
|
||
} = usePezkuwi();
|
||
|
||
const [selectedToken, setSelectedToken] = useState<Token | null>(null);
|
||
const [sendModalVisible, setSendModalVisible] = useState(false);
|
||
const [receiveModalVisible, setReceiveModalVisible] = useState(false);
|
||
const [createWalletModalVisible, setCreateWalletModalVisible] = useState(false);
|
||
const [importWalletModalVisible, setImportWalletModalVisible] = useState(false);
|
||
const [backupModalVisible, setBackupModalVisible] = useState(false);
|
||
const [networkSelectorVisible, setNetworkSelectorVisible] = useState(false);
|
||
const [walletSelectorVisible, setWalletSelectorVisible] = useState(false);
|
||
const [addTokenModalVisible, setAddTokenModalVisible] = useState(false);
|
||
const [recipientAddress, setRecipientAddress] = useState('');
|
||
const [sendAmount, setSendAmount] = useState('');
|
||
const [walletName, setWalletName] = useState('');
|
||
const [importMnemonic, setImportMnemonic] = useState('');
|
||
const [importWalletName, setImportWalletName] = useState('');
|
||
const [userMnemonic, setUserMnemonic] = useState<string>('');
|
||
const [isSending, setIsSending] = useState(false);
|
||
const [isLoadingBalances, setIsLoadingBalances] = useState(false);
|
||
|
||
// Transaction History State
|
||
const [transactions, setTransactions] = useState<Transaction[]>([]);
|
||
const [isLoadingHistory, setIsLoadingHistory] = useState(false);
|
||
|
||
const [balances, setBalances] = useState<{ [key: string]: string }>({
|
||
HEZ: '0.00',
|
||
PEZ: '0.00',
|
||
USDT: '0.00',
|
||
});
|
||
|
||
const tokens: Token[] = [
|
||
{
|
||
symbol: 'HEZ',
|
||
name: 'Pezkuwi',
|
||
balance: balances.HEZ,
|
||
value: '$0.00',
|
||
change: '+0.00%',
|
||
logo: hezLogo,
|
||
isLive: true
|
||
},
|
||
{
|
||
symbol: 'PEZ',
|
||
name: 'Pezkuwi Token',
|
||
balance: balances.PEZ,
|
||
value: '$0.00',
|
||
change: '+0.00%',
|
||
logo: pezLogo,
|
||
assetId: 1,
|
||
isLive: true
|
||
},
|
||
{
|
||
symbol: 'USDT',
|
||
name: 'Tether USD',
|
||
balance: balances.USDT,
|
||
value: '$0.00',
|
||
change: '+0.00%',
|
||
logo: usdtLogo,
|
||
assetId: 1000,
|
||
isLive: true
|
||
},
|
||
];
|
||
|
||
// Fetch balances and history
|
||
const fetchData = useCallback(async () => {
|
||
if (!api || !isApiReady || !selectedAccount) return;
|
||
|
||
setIsLoadingBalances(true);
|
||
try {
|
||
// 1. Fetch Balances
|
||
const accountInfo = await api.query.system.account(selectedAccount.address);
|
||
const hezBalance = (Number(accountInfo.data.free.toString()) / 1e12).toFixed(2);
|
||
|
||
let pezBalance = '0.00';
|
||
try {
|
||
if (api.query.assets?.account) {
|
||
const pezAsset = await api.query.assets.account(1, selectedAccount.address);
|
||
if (pezAsset.isSome) pezBalance = (Number(pezAsset.unwrap().balance.toString()) / 1e12).toFixed(2);
|
||
}
|
||
} catch {}
|
||
|
||
let usdtBalance = '0.00';
|
||
try {
|
||
if (api.query.assets?.account) {
|
||
// Check ID 1000 first (as per constants), fallback to 2 just in case
|
||
let usdtAsset = await api.query.assets.account(1000, selectedAccount.address);
|
||
if (usdtAsset.isNone) {
|
||
usdtAsset = await api.query.assets.account(2, selectedAccount.address);
|
||
}
|
||
|
||
if (usdtAsset.isSome) {
|
||
// USDT uses 6 decimals usually, checking constants or assuming standard
|
||
usdtBalance = (Number(usdtAsset.unwrap().balance.toString()) / 1e6).toFixed(2);
|
||
}
|
||
}
|
||
} catch {}
|
||
|
||
setBalances({ HEZ: hezBalance, PEZ: pezBalance, USDT: usdtBalance });
|
||
|
||
// 2. Fetch History from Indexer API (MUCH FASTER)
|
||
setIsLoadingHistory(true);
|
||
try {
|
||
const INDEXER_URL = 'http://172.31.134.70:3001'; // Update this to your local IP for physical device testing
|
||
const response = await fetch(`${INDEXER_URL}/api/history/${selectedAccount.address}`);
|
||
const data = await response.json();
|
||
|
||
const txList = data.map((tx: any) => ({
|
||
hash: tx.hash,
|
||
method: tx.asset_id ? 'transfer' : 'transfer',
|
||
section: tx.asset_id ? 'assets' : 'balances',
|
||
from: tx.sender,
|
||
to: tx.receiver,
|
||
amount: tx.amount,
|
||
blockNumber: tx.block_number,
|
||
isIncoming: tx.receiver === selectedAccount.address,
|
||
}));
|
||
|
||
setTransactions(txList);
|
||
} catch (e) {
|
||
console.warn('Indexer API unreachable, history not updated', e);
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error('Fetch error:', error);
|
||
} finally {
|
||
setIsLoadingBalances(false);
|
||
setIsLoadingHistory(false);
|
||
}
|
||
}, [api, isApiReady, selectedAccount]);
|
||
|
||
useEffect(() => {
|
||
fetchData();
|
||
const interval = setInterval(fetchData, 30000);
|
||
return () => clearInterval(interval);
|
||
}, [fetchData]);
|
||
|
||
const handleTokenPress = (token: Token) => {
|
||
if (!token.isLive) return;
|
||
setSelectedToken(token);
|
||
setSendModalVisible(true);
|
||
};
|
||
|
||
const handleSend = () => {
|
||
setSelectedToken(tokens[0]); // Default to HEZ
|
||
setSendModalVisible(true);
|
||
};
|
||
|
||
const handleReceive = () => {
|
||
setSelectedToken(tokens[0]);
|
||
setReceiveModalVisible(true);
|
||
};
|
||
|
||
const handleConfirmSend = async () => {
|
||
if (!recipientAddress || !sendAmount || !selectedToken || !selectedAccount || !api) {
|
||
showAlert('Error', 'Please enter recipient address and amount');
|
||
return;
|
||
}
|
||
|
||
setIsSending(true);
|
||
try {
|
||
const keypair = await getKeyPair(selectedAccount.address);
|
||
if (!keypair) throw new Error('Failed to load keypair');
|
||
|
||
// Adjust decimals based on token
|
||
const decimals = selectedToken.symbol === 'USDT' ? 1e6 : 1e12;
|
||
const amountInUnits = BigInt(Math.floor(parseFloat(sendAmount) * decimals));
|
||
|
||
let tx;
|
||
if (selectedToken.symbol === 'HEZ') {
|
||
tx = api.tx.balances.transfer(recipientAddress, amountInUnits);
|
||
} else if (selectedToken.assetId !== undefined) {
|
||
tx = api.tx.assets.transfer(selectedToken.assetId, recipientAddress, amountInUnits);
|
||
} else {
|
||
throw new Error('Unknown token type');
|
||
}
|
||
|
||
await tx.signAndSend(keypair, ({ status }) => {
|
||
if (status.isFinalized) {
|
||
setSendModalVisible(false);
|
||
setIsSending(false);
|
||
showAlert('Success', 'Transaction Sent!');
|
||
fetchData();
|
||
}
|
||
});
|
||
} catch (e: any) {
|
||
setIsSending(false);
|
||
showAlert('Error', e.message);
|
||
}
|
||
};
|
||
|
||
// Connect/Create Wallet handlers
|
||
const handleConnectWallet = async () => {
|
||
if (accounts.length === 0) setCreateWalletModalVisible(true);
|
||
else await connectWallet();
|
||
};
|
||
|
||
const handleCreateWallet = async () => {
|
||
try {
|
||
const { address, mnemonic } = await createWallet(walletName);
|
||
setUserMnemonic(mnemonic); // Save for backup
|
||
setCreateWalletModalVisible(false);
|
||
showAlert('Wallet Created', `Save this mnemonic:\n${mnemonic}`, [{ text: 'OK', onPress: () => connectWallet() }]);
|
||
} catch (e) { showAlert('Error', 'Failed'); }
|
||
};
|
||
|
||
// Copy Address Handler
|
||
const handleCopyAddress = () => {
|
||
if (!selectedAccount) return;
|
||
Clipboard.setString(selectedAccount.address);
|
||
showAlert('Copied!', 'Address copied to clipboard');
|
||
};
|
||
|
||
// Import Wallet Handler
|
||
const handleImportWallet = async () => {
|
||
if (!importMnemonic.trim()) {
|
||
showAlert('Error', 'Please enter a valid mnemonic');
|
||
return;
|
||
}
|
||
try {
|
||
// Use createWallet but inject mnemonic (you may need to modify PezkuwiContext)
|
||
// For now, basic implementation:
|
||
const { Keyring } = await import('@pezkuwi/keyring');
|
||
const keyring = new Keyring({ type: 'sr25519' });
|
||
const pair = keyring.addFromMnemonic(importMnemonic.trim());
|
||
|
||
// Store in AsyncStorage (via context method ideally)
|
||
showAlert('Success', `Wallet imported: ${pair.address.slice(0,8)}...`);
|
||
setImportWalletModalVisible(false);
|
||
setImportMnemonic('');
|
||
connectWallet();
|
||
} catch (e: any) {
|
||
showAlert('Error', e.message || 'Invalid mnemonic');
|
||
}
|
||
};
|
||
|
||
// Backup Mnemonic Handler
|
||
const handleBackupMnemonic = async () => {
|
||
if (!selectedAccount) {
|
||
showAlert('No Wallet', 'Please create or import a wallet first.');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// Retrieve mnemonic from secure storage
|
||
const seedKey = `pezkuwi_seed_${selectedAccount.address}`;
|
||
const storedMnemonic = await secureStorage.getItem(seedKey);
|
||
|
||
if (storedMnemonic) {
|
||
setUserMnemonic(storedMnemonic);
|
||
setBackupModalVisible(true);
|
||
} else {
|
||
showAlert('No Backup', 'Mnemonic not found in secure storage. It may have been imported from another device.');
|
||
}
|
||
} catch (error) {
|
||
console.error('Error retrieving mnemonic:', error);
|
||
showAlert('Error', 'Failed to retrieve mnemonic from secure storage.');
|
||
}
|
||
};
|
||
|
||
// Share QR Code
|
||
const handleShareQR = async () => {
|
||
if (!selectedAccount) return;
|
||
try {
|
||
await Share.share({
|
||
message: `My Pezkuwichain Address:\n${selectedAccount.address}`,
|
||
});
|
||
} catch (e) {
|
||
console.error(e);
|
||
}
|
||
};
|
||
|
||
// Network Switch Handler
|
||
const handleNetworkSwitch = async (network: NetworkType) => {
|
||
try {
|
||
await switchNetwork(network);
|
||
setNetworkSelectorVisible(false);
|
||
showAlert('Success', `Switched to ${NETWORKS[network].displayName}`);
|
||
} catch (e: any) {
|
||
showAlert('Error', e.message || 'Failed to switch network');
|
||
}
|
||
};
|
||
|
||
// Redirect to WalletSetupScreen if no wallet exists
|
||
useEffect(() => {
|
||
if (!selectedAccount && accounts.length === 0) {
|
||
navigation.replace('WalletSetup');
|
||
}
|
||
}, [selectedAccount, accounts, navigation]);
|
||
|
||
// Show loading while checking wallet state or redirecting
|
||
if (!selectedAccount && accounts.length === 0) {
|
||
return (
|
||
<SafeAreaView style={styles.container} testID="wallet-redirecting">
|
||
<View style={styles.loadingContainer}>
|
||
<ActivityIndicator size="large" color={KurdistanColors.kesk} />
|
||
<Text style={styles.loadingText}>Loading wallet...</Text>
|
||
</View>
|
||
</SafeAreaView>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<SafeAreaView style={styles.container} testID="wallet-screen">
|
||
<StatusBar barStyle="dark-content" />
|
||
|
||
{/* Top Header with Back Button */}
|
||
<View style={styles.topHeader} testID="wallet-top-header">
|
||
<TouchableOpacity onPress={() => navigation.goBack()} style={styles.backButton} testID="wallet-back-button">
|
||
<Text style={styles.backButtonText}>← Back</Text>
|
||
</TouchableOpacity>
|
||
<Text style={styles.topHeaderTitle}>Wallet</Text>
|
||
<TouchableOpacity onPress={() => setNetworkSelectorVisible(true)} testID="wallet-network-button">
|
||
<Text style={styles.networkBadge}>🌐 {NETWORKS[currentNetwork].displayName}</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
|
||
<ScrollView
|
||
style={styles.scrollContent}
|
||
refreshControl={<RefreshControl refreshing={isLoadingBalances} onRefresh={fetchData} />}
|
||
showsVerticalScrollIndicator={false}
|
||
testID="wallet-scroll-view"
|
||
>
|
||
{/* Wallet Selector Row */}
|
||
<View style={styles.walletSelectorRow}>
|
||
<TouchableOpacity
|
||
style={styles.walletSelector}
|
||
onPress={() => setWalletSelectorVisible(true)}
|
||
testID="wallet-selector-button"
|
||
>
|
||
<View style={styles.walletSelectorInfo}>
|
||
<Text style={styles.walletSelectorName}>{selectedAccount?.name || 'Wallet'}</Text>
|
||
<Text style={styles.walletSelectorAddress} numberOfLines={1}>
|
||
{selectedAccount?.address ? `${selectedAccount.address.slice(0, 8)}...${selectedAccount.address.slice(-6)}` : ''}
|
||
</Text>
|
||
</View>
|
||
<Text style={styles.walletSelectorArrow}>▼</Text>
|
||
</TouchableOpacity>
|
||
<View style={styles.walletHeaderButtons}>
|
||
<TouchableOpacity
|
||
style={styles.addWalletButton}
|
||
onPress={() => navigation.navigate('WalletSetup')}
|
||
testID="add-wallet-button"
|
||
>
|
||
<Text style={styles.addWalletIcon}>+</Text>
|
||
</TouchableOpacity>
|
||
<TouchableOpacity
|
||
style={styles.scanButton}
|
||
onPress={() => showAlert('Scan', 'QR Scanner coming soon')}
|
||
testID="wallet-scan-button"
|
||
>
|
||
<Text style={styles.scanIcon}>⊡</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
</View>
|
||
|
||
{/* Main Token Cards - HEZ and PEZ side by side */}
|
||
<View style={styles.mainTokensRow}>
|
||
{/* HEZ Card */}
|
||
<TouchableOpacity style={styles.mainTokenCard} onPress={() => handleTokenPress(tokens[0])}>
|
||
<View style={styles.mainTokenLogoContainer}>
|
||
<HezTokenLogo size={56} />
|
||
</View>
|
||
<Text style={styles.mainTokenSymbol}>HEZ</Text>
|
||
<Text style={styles.mainTokenBalance}>{balances.HEZ}</Text>
|
||
<Text style={styles.mainTokenSubtitle}>Welati Coin</Text>
|
||
</TouchableOpacity>
|
||
|
||
{/* PEZ Card */}
|
||
<TouchableOpacity style={styles.mainTokenCard} onPress={() => handleTokenPress(tokens[1])}>
|
||
<View style={styles.mainTokenLogoContainer}>
|
||
<PezTokenLogo size={56} />
|
||
</View>
|
||
<Text style={styles.mainTokenSymbol}>PEZ</Text>
|
||
<Text style={styles.mainTokenBalance}>{balances.PEZ}</Text>
|
||
<Text style={styles.mainTokenSubtitle}>Pezkuwichain Token</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
|
||
{/* Action Buttons Grid - 1x4 */}
|
||
<View style={styles.actionsGrid}>
|
||
<TouchableOpacity style={[styles.actionButton, {backgroundColor: '#22C55E'}]} onPress={handleSend}>
|
||
<Text style={styles.actionIcon}>↑</Text>
|
||
<Text style={styles.actionLabel}>Send</Text>
|
||
</TouchableOpacity>
|
||
|
||
<TouchableOpacity style={[styles.actionButton, {backgroundColor: '#3B82F6'}]} onPress={handleReceive}>
|
||
<Text style={styles.actionIcon}>↓</Text>
|
||
<Text style={styles.actionLabel}>Receive</Text>
|
||
</TouchableOpacity>
|
||
|
||
<TouchableOpacity style={[styles.actionButton, {backgroundColor: '#6B7280'}]} onPress={() => navigation.navigate('Swap')}>
|
||
<Text style={styles.actionIcon}>🔄</Text>
|
||
<Text style={styles.actionLabel}>Swap</Text>
|
||
</TouchableOpacity>
|
||
|
||
<TouchableOpacity style={[styles.actionButton, {backgroundColor: '#10B981'}]} onPress={() => showAlert('Staking', 'Navigate to Staking')}>
|
||
<Text style={styles.actionIcon}>🥩</Text>
|
||
<Text style={styles.actionLabel}>Staking</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
|
||
{/* Tokens List */}
|
||
<View style={styles.tokensSection}>
|
||
<View style={styles.tokensSectionHeader}>
|
||
<Text style={styles.tokensTitle}>Tokens</Text>
|
||
<View style={styles.tokenHeaderIcons}>
|
||
<TouchableOpacity style={styles.tokenHeaderIcon}>
|
||
<Text>🔍</Text>
|
||
</TouchableOpacity>
|
||
<TouchableOpacity style={styles.tokenHeaderIcon} onPress={() => setAddTokenModalVisible(true)}>
|
||
<Text>➕</Text>
|
||
</TouchableOpacity>
|
||
<TouchableOpacity style={styles.tokenHeaderIcon} onPress={handleBackupMnemonic}>
|
||
<Text>⚙️</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
</View>
|
||
|
||
{/* USDT */}
|
||
<TouchableOpacity style={styles.tokenListItem}>
|
||
<Image source={usdtLogo} style={styles.tokenListLogo} resizeMode="contain" />
|
||
<View style={styles.tokenListInfo}>
|
||
<Text style={styles.tokenListSymbol}>USDT</Text>
|
||
<Text style={styles.tokenListNetwork}>PEZ Network</Text>
|
||
</View>
|
||
<View style={styles.tokenListBalance}>
|
||
<Text style={styles.tokenListAmount}>{balances.USDT}</Text>
|
||
<Text style={styles.tokenListUsdValue}>$0.00</Text>
|
||
</View>
|
||
</TouchableOpacity>
|
||
|
||
{/* DOT */}
|
||
<TouchableOpacity style={styles.tokenListItem}>
|
||
<Image source={dotLogo} style={styles.tokenListLogo} resizeMode="contain" />
|
||
<View style={styles.tokenListInfo}>
|
||
<Text style={styles.tokenListSymbol}>DOT</Text>
|
||
<Text style={styles.tokenListNetwork}>Polkadot</Text>
|
||
</View>
|
||
<View style={styles.tokenListBalance}>
|
||
<Text style={styles.tokenListAmount}>0.00</Text>
|
||
<Text style={styles.tokenListUsdValue}>$0.00</Text>
|
||
</View>
|
||
</TouchableOpacity>
|
||
</View>
|
||
|
||
<View style={{height: 100}} />
|
||
</ScrollView>
|
||
|
||
{/* Modals */}
|
||
<Modal visible={sendModalVisible} transparent animationType="slide" onRequestClose={() => setSendModalVisible(false)}>
|
||
<View style={styles.modalOverlay}>
|
||
<View style={styles.modalCard}>
|
||
<Text style={styles.modalHeader}>Send {selectedToken?.symbol}</Text>
|
||
<View style={{alignItems:'center', marginBottom:16}}>
|
||
{selectedToken && <Image source={selectedToken.logo} style={{width:48, height:48}} />}
|
||
</View>
|
||
<TextInput style={styles.inputField} placeholder="Address" value={recipientAddress} onChangeText={setRecipientAddress} />
|
||
<TextInput style={styles.inputField} placeholder="Amount" keyboardType="numeric" value={sendAmount} onChangeText={setSendAmount} />
|
||
<View style={styles.modalActions}>
|
||
<TouchableOpacity style={styles.btnCancel} onPress={() => setSendModalVisible(false)}><Text>Cancel</Text></TouchableOpacity>
|
||
<TouchableOpacity style={styles.btnConfirm} onPress={handleConfirmSend} disabled={isSending}>
|
||
<Text style={{color:'white'}}>{isSending ? 'Sending...' : 'Confirm'}</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
</Modal>
|
||
|
||
<Modal visible={receiveModalVisible} transparent animationType="slide" onRequestClose={() => setReceiveModalVisible(false)}>
|
||
<View style={styles.modalOverlay}>
|
||
<View style={styles.modalCard}>
|
||
<Text style={styles.modalHeader}>Receive Address</Text>
|
||
<View style={{alignItems:'center', marginVertical: 20}}>
|
||
{selectedAccount && <QRCode value={selectedAccount.address} size={180}/>}
|
||
</View>
|
||
<Text style={styles.addrFull}>{selectedAccount?.address}</Text>
|
||
<View style={styles.modalActions}>
|
||
<TouchableOpacity style={styles.btnCancel} onPress={handleCopyAddress}>
|
||
<Text>📋 Copy</Text>
|
||
</TouchableOpacity>
|
||
<TouchableOpacity style={styles.btnCancel} onPress={handleShareQR}>
|
||
<Text>📤 Share</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
<TouchableOpacity style={[styles.btnConfirm, {width: '100%', marginTop: 8}]} onPress={() => setReceiveModalVisible(false)}>
|
||
<Text style={{color:'white'}}>Close</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
</View>
|
||
</Modal>
|
||
|
||
{/* Backup Mnemonic Modal */}
|
||
<Modal visible={backupModalVisible} transparent animationType="slide" onRequestClose={() => setBackupModalVisible(false)}>
|
||
<View style={styles.modalOverlay}>
|
||
<View style={styles.modalCard}>
|
||
<Text style={styles.modalHeader}>🔐 Backup Mnemonic</Text>
|
||
<Text style={{color: 'red', fontSize: 12, marginBottom: 12, textAlign: 'center'}}>
|
||
⚠️ NEVER share this with anyone! Write it down and store safely.
|
||
</Text>
|
||
<View style={[styles.inputField, {backgroundColor: '#FFF9E6', padding: 16, minHeight: 100}]}>
|
||
<Text style={{fontSize: 14, lineHeight: 22}}>{userMnemonic}</Text>
|
||
</View>
|
||
<View style={styles.modalActions}>
|
||
<TouchableOpacity style={styles.btnCancel} onPress={() => {
|
||
Clipboard.setString(userMnemonic);
|
||
showAlert('Copied', 'Mnemonic copied to clipboard');
|
||
}}>
|
||
<Text>📋 Copy</Text>
|
||
</TouchableOpacity>
|
||
<TouchableOpacity style={styles.btnConfirm} onPress={() => setBackupModalVisible(false)}>
|
||
<Text style={{color:'white'}}>Close</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
</Modal>
|
||
|
||
{/* Wallet Selector Modal */}
|
||
<Modal visible={walletSelectorVisible} transparent animationType="slide" onRequestClose={() => setWalletSelectorVisible(false)}>
|
||
<View style={styles.modalOverlay}>
|
||
<View style={styles.modalCard}>
|
||
<Text style={styles.modalHeader}>👛 My Wallets</Text>
|
||
<Text style={{color: '#666', fontSize: 12, marginBottom: 16, textAlign: 'center'}}>
|
||
Select a wallet or create a new one
|
||
</Text>
|
||
|
||
{/* Wallet List */}
|
||
{accounts.map((account) => {
|
||
const isSelected = account.address === selectedAccount?.address;
|
||
return (
|
||
<View key={account.address} style={styles.walletOptionRow}>
|
||
<TouchableOpacity
|
||
style={[
|
||
styles.walletOption,
|
||
isSelected && styles.walletOptionSelected,
|
||
{flex: 1, marginBottom: 0}
|
||
]}
|
||
onPress={() => {
|
||
setSelectedAccount(account);
|
||
setWalletSelectorVisible(false);
|
||
}}
|
||
>
|
||
<View style={styles.walletOptionIcon}>
|
||
<Text style={{fontSize: 24}}>👛</Text>
|
||
</View>
|
||
<View style={{flex: 1}}>
|
||
<Text style={[styles.walletOptionName, isSelected && {color: KurdistanColors.kesk}]}>
|
||
{account.name}
|
||
</Text>
|
||
<Text style={styles.walletOptionAddress} numberOfLines={1}>
|
||
{account.address.slice(0, 12)}...{account.address.slice(-8)}
|
||
</Text>
|
||
</View>
|
||
{isSelected && <Text style={{fontSize: 20, color: KurdistanColors.kesk}}>✓</Text>}
|
||
</TouchableOpacity>
|
||
<TouchableOpacity
|
||
style={styles.deleteWalletButton}
|
||
onPress={async () => {
|
||
const confirmDelete = Platform.OS === 'web'
|
||
? window.confirm(`Delete "${account.name}"?\n\nThis action cannot be undone. Make sure you have backed up your recovery phrase.`)
|
||
: await new Promise<boolean>((resolve) => {
|
||
Alert.alert(
|
||
'Delete Wallet',
|
||
`Are you sure you want to delete "${account.name}"?\n\nThis action cannot be undone. Make sure you have backed up your recovery phrase.`,
|
||
[
|
||
{ text: 'Cancel', style: 'cancel', onPress: () => resolve(false) },
|
||
{ text: 'Delete', style: 'destructive', onPress: () => resolve(true) }
|
||
]
|
||
);
|
||
});
|
||
|
||
if (confirmDelete) {
|
||
try {
|
||
await deleteWallet(account.address);
|
||
if (accounts.length <= 1) {
|
||
setWalletSelectorVisible(false);
|
||
}
|
||
} catch (err) {
|
||
if (Platform.OS === 'web') {
|
||
window.alert('Failed to delete wallet');
|
||
} else {
|
||
Alert.alert('Error', 'Failed to delete wallet');
|
||
}
|
||
}
|
||
}
|
||
}}
|
||
>
|
||
<Text style={styles.deleteWalletIcon}>🗑️</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
);
|
||
})}
|
||
|
||
{/* Add New Wallet Button */}
|
||
<TouchableOpacity
|
||
style={styles.addNewWalletOption}
|
||
onPress={() => {
|
||
setWalletSelectorVisible(false);
|
||
navigation.navigate('WalletSetup');
|
||
}}
|
||
>
|
||
<View style={styles.addNewWalletIcon}>
|
||
<Text style={{fontSize: 24, color: KurdistanColors.kesk}}>+</Text>
|
||
</View>
|
||
<Text style={styles.addNewWalletText}>Add New Wallet</Text>
|
||
</TouchableOpacity>
|
||
|
||
<TouchableOpacity style={styles.btnConfirm} onPress={() => setWalletSelectorVisible(false)}>
|
||
<Text style={{color:'white'}}>Close</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
</View>
|
||
</Modal>
|
||
|
||
{/* Network Selector Modal */}
|
||
<Modal visible={networkSelectorVisible} transparent animationType="slide" onRequestClose={() => setNetworkSelectorVisible(false)}>
|
||
<View style={styles.modalOverlay}>
|
||
<View style={styles.modalCard}>
|
||
<Text style={styles.modalHeader}>🌐 Select Network</Text>
|
||
<Text style={{color: '#666', fontSize: 12, marginBottom: 16, textAlign: 'center'}}>
|
||
Choose the network you want to connect to
|
||
</Text>
|
||
{(Object.keys(NETWORKS) as NetworkType[]).map((networkKey) => {
|
||
const network = NETWORKS[networkKey];
|
||
const isSelected = networkKey === currentNetwork;
|
||
return (
|
||
<TouchableOpacity
|
||
key={networkKey}
|
||
style={[
|
||
styles.networkOption,
|
||
isSelected && styles.networkOptionSelected
|
||
]}
|
||
onPress={() => handleNetworkSwitch(networkKey)}
|
||
>
|
||
<View style={{flex: 1}}>
|
||
<Text style={[styles.networkName, isSelected && {color: KurdistanColors.kesk}]}>
|
||
{network.displayName}
|
||
</Text>
|
||
<Text style={styles.networkType}>
|
||
{network.type === 'mainnet' ? '🟢 Mainnet' : network.type === 'testnet' ? '🟡 Testnet' : '🟠 Canary'}
|
||
</Text>
|
||
</View>
|
||
{isSelected && <Text style={{fontSize: 20}}>✓</Text>}
|
||
</TouchableOpacity>
|
||
);
|
||
})}
|
||
<TouchableOpacity style={styles.btnConfirm} onPress={() => setNetworkSelectorVisible(false)}>
|
||
<Text style={{color:'white'}}>Close</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
</View>
|
||
</Modal>
|
||
|
||
{/* Add Token Modal */}
|
||
<AddTokenModal
|
||
visible={addTokenModalVisible}
|
||
onClose={() => setAddTokenModalVisible(false)}
|
||
onTokenAdded={fetchData}
|
||
/>
|
||
|
||
</SafeAreaView>
|
||
);
|
||
};
|
||
|
||
const styles = StyleSheet.create({
|
||
container: {
|
||
flex: 1,
|
||
backgroundColor: '#F8F9FA'
|
||
},
|
||
scrollContent: {
|
||
flex: 1,
|
||
},
|
||
loadingContainer: {
|
||
flex: 1,
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
},
|
||
loadingText: {
|
||
marginTop: 16,
|
||
fontSize: 16,
|
||
color: '#666',
|
||
},
|
||
|
||
// Top Header with Back Button
|
||
topHeader: {
|
||
flexDirection: 'row',
|
||
justifyContent: 'space-between',
|
||
alignItems: 'center',
|
||
paddingHorizontal: 16,
|
||
paddingVertical: 12,
|
||
backgroundColor: '#FFFFFF',
|
||
borderBottomWidth: 1,
|
||
borderBottomColor: '#E5E5E5',
|
||
},
|
||
backButton: {
|
||
paddingVertical: 4,
|
||
paddingRight: 8,
|
||
},
|
||
backButtonText: {
|
||
fontSize: 16,
|
||
color: KurdistanColors.kesk,
|
||
fontWeight: '500',
|
||
},
|
||
topHeaderTitle: {
|
||
fontSize: 18,
|
||
fontWeight: '600',
|
||
color: '#333',
|
||
},
|
||
|
||
// Header Styles (New Design)
|
||
headerContainer: {
|
||
flexDirection: 'row',
|
||
justifyContent: 'space-between',
|
||
alignItems: 'center',
|
||
paddingHorizontal: 20,
|
||
paddingTop: Platform.OS === 'android' ? 16 : 12,
|
||
paddingBottom: 16,
|
||
backgroundColor: '#FFFFFF',
|
||
},
|
||
walletTitle: {
|
||
fontSize: 22,
|
||
fontWeight: 'bold',
|
||
color: '#333',
|
||
},
|
||
networkBadge: {
|
||
fontSize: 14,
|
||
color: KurdistanColors.kesk,
|
||
backgroundColor: 'rgba(0, 143, 67, 0.1)',
|
||
paddingHorizontal: 12,
|
||
paddingVertical: 6,
|
||
borderRadius: 16,
|
||
overflow: 'hidden',
|
||
},
|
||
scanButton: {
|
||
width: 40,
|
||
height: 40,
|
||
borderRadius: 20,
|
||
backgroundColor: '#F5F5F5',
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
},
|
||
scanIcon: {
|
||
fontSize: 20,
|
||
color: '#333',
|
||
},
|
||
|
||
// Main Token Cards (HEZ & PEZ) - New Design
|
||
mainTokensRow: {
|
||
flexDirection: 'row',
|
||
paddingHorizontal: 16,
|
||
paddingVertical: 16,
|
||
gap: 12,
|
||
},
|
||
mainTokenCard: {
|
||
flex: 1,
|
||
backgroundColor: '#FFFFFF',
|
||
borderRadius: 20,
|
||
padding: 20,
|
||
alignItems: 'center',
|
||
boxShadow: '0px 2px 8px rgba(0, 0, 0, 0.08)',
|
||
elevation: 4,
|
||
},
|
||
mainTokenLogo: {
|
||
width: 56,
|
||
height: 56,
|
||
marginBottom: 12,
|
||
},
|
||
mainTokenLogoContainer: {
|
||
width: 56,
|
||
height: 56,
|
||
marginBottom: 12,
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
},
|
||
mainTokenSymbol: {
|
||
fontSize: 18,
|
||
fontWeight: 'bold',
|
||
color: '#333',
|
||
marginBottom: 8,
|
||
},
|
||
mainTokenBalance: {
|
||
fontSize: 24,
|
||
fontWeight: 'bold',
|
||
color: KurdistanColors.kesk,
|
||
marginBottom: 4,
|
||
},
|
||
mainTokenSubtitle: {
|
||
fontSize: 11,
|
||
color: '#888',
|
||
},
|
||
|
||
// Action Buttons Grid (2x4) - New Design
|
||
actionsGrid: {
|
||
flexDirection: 'row',
|
||
flexWrap: 'wrap',
|
||
paddingHorizontal: 16,
|
||
paddingVertical: 8,
|
||
gap: 12,
|
||
},
|
||
actionButton: {
|
||
width: '23%',
|
||
aspectRatio: 1,
|
||
borderRadius: 16,
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)',
|
||
elevation: 3,
|
||
},
|
||
actionIcon: {
|
||
fontSize: 24,
|
||
color: '#FFFFFF',
|
||
marginBottom: 4,
|
||
},
|
||
actionLabel: {
|
||
fontSize: 11,
|
||
fontWeight: '600',
|
||
color: '#FFFFFF',
|
||
},
|
||
|
||
// Tokens List Section - New Design
|
||
tokensSection: {
|
||
paddingHorizontal: 16,
|
||
paddingTop: 20,
|
||
},
|
||
tokensSectionHeader: {
|
||
flexDirection: 'row',
|
||
justifyContent: 'space-between',
|
||
alignItems: 'center',
|
||
marginBottom: 16,
|
||
paddingHorizontal: 4,
|
||
},
|
||
tokensTitle: {
|
||
fontSize: 20,
|
||
fontWeight: 'bold',
|
||
color: '#333',
|
||
},
|
||
tokenHeaderIcons: {
|
||
flexDirection: 'row',
|
||
gap: 12,
|
||
},
|
||
tokenHeaderIcon: {
|
||
width: 36,
|
||
height: 36,
|
||
borderRadius: 18,
|
||
backgroundColor: '#F5F5F5',
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
},
|
||
tokenListItem: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
backgroundColor: '#FFFFFF',
|
||
borderRadius: 16,
|
||
padding: 16,
|
||
marginBottom: 12,
|
||
boxShadow: '0px 1px 4px rgba(0, 0, 0, 0.05)',
|
||
elevation: 2,
|
||
},
|
||
tokenListLogo: {
|
||
width: 44,
|
||
height: 44,
|
||
marginRight: 12,
|
||
},
|
||
tokenListInfo: {
|
||
flex: 1,
|
||
},
|
||
tokenListSymbol: {
|
||
fontSize: 16,
|
||
fontWeight: 'bold',
|
||
color: '#333',
|
||
marginBottom: 2,
|
||
},
|
||
tokenListNetwork: {
|
||
fontSize: 12,
|
||
color: '#888',
|
||
},
|
||
tokenListBalance: {
|
||
alignItems: 'flex-end',
|
||
},
|
||
tokenListAmount: {
|
||
fontSize: 16,
|
||
fontWeight: 'bold',
|
||
color: '#333',
|
||
marginBottom: 2,
|
||
},
|
||
tokenListUsdValue: {
|
||
fontSize: 12,
|
||
color: '#888',
|
||
},
|
||
|
||
// Modal Styles
|
||
modalOverlay: {
|
||
flex: 1,
|
||
backgroundColor: 'rgba(0,0,0,0.5)',
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
padding: 20
|
||
},
|
||
modalCard: {
|
||
backgroundColor: 'white',
|
||
borderRadius: 20,
|
||
padding: 24,
|
||
width: '100%',
|
||
alignItems: 'center'
|
||
},
|
||
modalHeader: {
|
||
fontSize: 20,
|
||
fontWeight: 'bold',
|
||
marginBottom: 20
|
||
},
|
||
inputField: {
|
||
width: '100%',
|
||
backgroundColor: '#F5F5F5',
|
||
padding: 16,
|
||
borderRadius: 12,
|
||
marginBottom: 12
|
||
},
|
||
modalActions: {
|
||
flexDirection: 'row',
|
||
width: '100%',
|
||
gap: 12,
|
||
marginTop: 10
|
||
},
|
||
btnCancel: {
|
||
flex: 1,
|
||
padding: 16,
|
||
borderRadius: 12,
|
||
backgroundColor: '#EEE',
|
||
alignItems: 'center'
|
||
},
|
||
btnConfirm: {
|
||
flex: 1,
|
||
padding: 16,
|
||
borderRadius: 12,
|
||
backgroundColor: KurdistanColors.kesk,
|
||
alignItems: 'center'
|
||
},
|
||
addrFull: {
|
||
textAlign: 'center',
|
||
color: '#666',
|
||
fontSize: 12,
|
||
marginVertical: 10,
|
||
fontFamily: 'monospace'
|
||
},
|
||
|
||
// Network Selector Styles
|
||
networkOption: {
|
||
flexDirection: 'row',
|
||
width: '100%',
|
||
padding: 16,
|
||
borderRadius: 12,
|
||
backgroundColor: '#F5F5F5',
|
||
marginBottom: 8,
|
||
alignItems: 'center'
|
||
},
|
||
networkOptionSelected: {
|
||
backgroundColor: 'rgba(0, 143, 67, 0.1)',
|
||
borderWidth: 2,
|
||
borderColor: KurdistanColors.kesk
|
||
},
|
||
networkName: {
|
||
fontSize: 16,
|
||
fontWeight: '600',
|
||
color: '#333'
|
||
},
|
||
networkType: {
|
||
fontSize: 12,
|
||
color: '#666',
|
||
marginTop: 4
|
||
},
|
||
|
||
// Welcome Screen Styles
|
||
welcomeGradient: {
|
||
flex: 0.45,
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
borderBottomLeftRadius: 32,
|
||
borderBottomRightRadius: 32,
|
||
},
|
||
welcomeContent: {
|
||
alignItems: 'center',
|
||
paddingHorizontal: 20,
|
||
},
|
||
welcomeEmoji: {
|
||
fontSize: 64,
|
||
marginBottom: 16,
|
||
},
|
||
welcomeTitle: {
|
||
fontSize: 18,
|
||
color: 'rgba(255,255,255,0.8)',
|
||
marginBottom: 8,
|
||
},
|
||
welcomeBrand: {
|
||
fontSize: 32,
|
||
fontWeight: 'bold',
|
||
color: 'white',
|
||
marginBottom: 8,
|
||
textAlign: 'center',
|
||
},
|
||
welcomeSubtitle: {
|
||
fontSize: 16,
|
||
color: 'rgba(255,255,255,0.7)',
|
||
textAlign: 'center',
|
||
},
|
||
|
||
// Button Container (Welcome Screen)
|
||
buttonContainer: {
|
||
flex: 0.55,
|
||
paddingHorizontal: 24,
|
||
paddingTop: 32,
|
||
justifyContent: 'flex-start',
|
||
},
|
||
|
||
// Primary Button (Welcome Screen)
|
||
primaryWalletButton: {
|
||
marginBottom: 16,
|
||
borderRadius: 16,
|
||
overflow: 'hidden',
|
||
boxShadow: '0px 4px 8px rgba(0, 128, 0, 0.3)',
|
||
elevation: 8,
|
||
},
|
||
buttonGradient: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
padding: 20,
|
||
borderRadius: 16,
|
||
},
|
||
buttonIcon: {
|
||
width: 52,
|
||
height: 52,
|
||
borderRadius: 26,
|
||
backgroundColor: 'rgba(255,255,255,0.2)',
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
marginRight: 16,
|
||
},
|
||
buttonIconText: {
|
||
fontSize: 24,
|
||
color: 'white',
|
||
},
|
||
buttonTextContainer: {
|
||
flex: 1,
|
||
},
|
||
primaryButtonText: {
|
||
fontSize: 18,
|
||
fontWeight: 'bold',
|
||
color: 'white',
|
||
marginBottom: 4,
|
||
},
|
||
primaryButtonSubtext: {
|
||
fontSize: 14,
|
||
color: 'rgba(255,255,255,0.8)',
|
||
},
|
||
|
||
// Secondary Button (Welcome Screen)
|
||
secondaryWalletButton: {
|
||
backgroundColor: 'white',
|
||
borderRadius: 16,
|
||
marginBottom: 24,
|
||
boxShadow: '0px 2px 8px rgba(0, 0, 0, 0.1)',
|
||
elevation: 4,
|
||
},
|
||
secondaryButtonContent: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
padding: 20,
|
||
},
|
||
secondaryButtonText: {
|
||
fontSize: 18,
|
||
fontWeight: '600',
|
||
color: '#333',
|
||
marginBottom: 4,
|
||
},
|
||
secondaryButtonSubtext: {
|
||
fontSize: 14,
|
||
color: '#666',
|
||
},
|
||
|
||
// Security Notice (Welcome Screen)
|
||
securityNotice: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
backgroundColor: 'rgba(0,105,62,0.05)',
|
||
padding: 16,
|
||
borderRadius: 12,
|
||
marginTop: 'auto',
|
||
marginBottom: 20,
|
||
},
|
||
securityIcon: {
|
||
fontSize: 20,
|
||
marginRight: 12,
|
||
},
|
||
securityText: {
|
||
flex: 1,
|
||
fontSize: 12,
|
||
color: '#666',
|
||
lineHeight: 18,
|
||
},
|
||
// Wallet Selector Row
|
||
walletSelectorRow: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
justifyContent: 'space-between',
|
||
paddingHorizontal: 16,
|
||
paddingVertical: 12,
|
||
marginBottom: 8,
|
||
},
|
||
walletSelector: {
|
||
flex: 1,
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
backgroundColor: '#FFFFFF',
|
||
borderRadius: 12,
|
||
padding: 12,
|
||
marginRight: 12,
|
||
boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.05)',
|
||
elevation: 2,
|
||
},
|
||
walletSelectorInfo: {
|
||
flex: 1,
|
||
},
|
||
walletSelectorName: {
|
||
fontSize: 16,
|
||
fontWeight: '600',
|
||
color: KurdistanColors.reş,
|
||
},
|
||
walletSelectorAddress: {
|
||
fontSize: 12,
|
||
color: '#999',
|
||
marginTop: 2,
|
||
},
|
||
walletSelectorArrow: {
|
||
fontSize: 12,
|
||
color: '#666',
|
||
marginLeft: 8,
|
||
},
|
||
walletHeaderButtons: {
|
||
flexDirection: 'row',
|
||
gap: 8,
|
||
},
|
||
addWalletButton: {
|
||
width: 44,
|
||
height: 44,
|
||
borderRadius: 12,
|
||
backgroundColor: '#FFFFFF',
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.05)',
|
||
elevation: 2,
|
||
},
|
||
addWalletIcon: {
|
||
fontSize: 24,
|
||
color: KurdistanColors.kesk,
|
||
fontWeight: '300',
|
||
},
|
||
// Wallet Selector Modal
|
||
walletOption: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
padding: 16,
|
||
backgroundColor: '#F8F9FA',
|
||
borderRadius: 12,
|
||
marginBottom: 8,
|
||
borderWidth: 2,
|
||
borderColor: 'transparent',
|
||
},
|
||
walletOptionSelected: {
|
||
borderColor: KurdistanColors.kesk,
|
||
backgroundColor: 'rgba(0, 143, 67, 0.05)',
|
||
},
|
||
walletOptionIcon: {
|
||
width: 48,
|
||
height: 48,
|
||
borderRadius: 24,
|
||
backgroundColor: '#FFFFFF',
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
marginRight: 12,
|
||
},
|
||
walletOptionName: {
|
||
fontSize: 16,
|
||
fontWeight: '600',
|
||
color: KurdistanColors.reş,
|
||
},
|
||
walletOptionAddress: {
|
||
fontSize: 12,
|
||
color: '#999',
|
||
marginTop: 2,
|
||
},
|
||
addNewWalletOption: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
padding: 16,
|
||
backgroundColor: 'rgba(0, 143, 67, 0.05)',
|
||
borderRadius: 12,
|
||
marginBottom: 16,
|
||
borderWidth: 2,
|
||
borderColor: KurdistanColors.kesk,
|
||
borderStyle: 'dashed',
|
||
},
|
||
addNewWalletIcon: {
|
||
width: 48,
|
||
height: 48,
|
||
borderRadius: 24,
|
||
backgroundColor: '#FFFFFF',
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
marginRight: 12,
|
||
},
|
||
addNewWalletText: {
|
||
fontSize: 16,
|
||
fontWeight: '600',
|
||
color: KurdistanColors.kesk,
|
||
},
|
||
// Delete wallet
|
||
walletOptionRow: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
marginBottom: 8,
|
||
gap: 8,
|
||
},
|
||
deleteWalletButton: {
|
||
width: 44,
|
||
height: 44,
|
||
borderRadius: 12,
|
||
backgroundColor: 'rgba(239, 68, 68, 0.1)',
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
},
|
||
deleteWalletIcon: {
|
||
fontSize: 18,
|
||
},
|
||
});
|
||
|
||
export default WalletScreen; |