mirror of
https://github.com/pezkuwichain/pezkuwi-mobile-app.git
synced 2026-06-14 10:11:02 +00:00
auto-commit for bed65b0f-c949-4d15-b953-0bf08c7c9e55
This commit is contained in:
@@ -0,0 +1,225 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
Modal,
|
||||
TouchableOpacity,
|
||||
Image,
|
||||
Alert,
|
||||
Share,
|
||||
} from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import QRCode from 'react-native-qrcode-svg';
|
||||
import * as Clipboard from 'expo-clipboard';
|
||||
import Colors from '../constants/colors';
|
||||
import { Typography, Spacing, BorderRadius, Shadow } from '../constants/theme';
|
||||
|
||||
interface ReceiveModalProps {
|
||||
visible: boolean;
|
||||
onClose: () => void;
|
||||
token: {
|
||||
symbol: string;
|
||||
name: string;
|
||||
icon: any;
|
||||
color: string;
|
||||
};
|
||||
}
|
||||
|
||||
export default function ReceiveModal({ visible, onClose, token }: ReceiveModalProps) {
|
||||
// Mock wallet address - in production, this would come from user's wallet
|
||||
const walletAddress = 'pezkuwi1a2b3c4d5e6f7g8h9i0j';
|
||||
const network = 'Optimism';
|
||||
|
||||
const handleCopyAddress = async () => {
|
||||
await Clipboard.setStringAsync(walletAddress);
|
||||
Alert.alert('Copied!', 'Wallet address copied to clipboard');
|
||||
};
|
||||
|
||||
const handleShareAddress = async () => {
|
||||
try {
|
||||
await Share.share({
|
||||
message: `My ${token.symbol} wallet address:\n${walletAddress}\n\nNetwork: ${network}`,
|
||||
title: `${token.symbol} Wallet Address`,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error sharing:', error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
visible={visible}
|
||||
transparent
|
||||
animationType="slide"
|
||||
onRequestClose={onClose}
|
||||
>
|
||||
<View style={styles.overlay}>
|
||||
<View style={styles.modalContainer}>
|
||||
{/* Close Button */}
|
||||
<TouchableOpacity style={styles.closeButton} onPress={onClose}>
|
||||
<Ionicons name="close" size={28} color={Colors.textDark} />
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* Token Icon */}
|
||||
<Image source={token.icon} style={styles.tokenIcon} />
|
||||
|
||||
{/* Title */}
|
||||
<Text style={styles.title}>Receive {token.symbol}</Text>
|
||||
|
||||
{/* QR Code Card */}
|
||||
<View style={styles.qrCard}>
|
||||
<QRCode value={walletAddress} size={200} />
|
||||
</View>
|
||||
|
||||
{/* Wallet Address */}
|
||||
<TouchableOpacity
|
||||
style={styles.addressContainer}
|
||||
onPress={handleCopyAddress}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Text style={styles.addressText}>{walletAddress}</Text>
|
||||
<Ionicons name="copy-outline" size={20} color={Colors.primary} />
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.tapToCopy}>Tap to copy</Text>
|
||||
|
||||
{/* Network Badge */}
|
||||
<View style={styles.networkBadge}>
|
||||
<Ionicons name="globe-outline" size={20} color="#007AFF" />
|
||||
<Text style={styles.networkText}>{network} Network</Text>
|
||||
</View>
|
||||
|
||||
{/* Share Button */}
|
||||
<TouchableOpacity style={styles.shareButton} onPress={handleShareAddress}>
|
||||
<Ionicons name="share-outline" size={20} color={Colors.textDark} />
|
||||
<Text style={styles.shareButtonText}>Share Address</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* Warning Box */}
|
||||
<View style={styles.warningBox}>
|
||||
<Ionicons name="warning-outline" size={24} color="#F59E0B" />
|
||||
<Text style={styles.warningText}>
|
||||
Only send {token.symbol} to this address on {network} network
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
overlay: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: Spacing.lg,
|
||||
},
|
||||
modalContainer: {
|
||||
width: '100%',
|
||||
maxWidth: 400,
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: BorderRadius.xl,
|
||||
padding: Spacing.xl,
|
||||
...Shadow.medium,
|
||||
},
|
||||
closeButton: {
|
||||
position: 'absolute',
|
||||
top: Spacing.md,
|
||||
right: Spacing.md,
|
||||
zIndex: 1,
|
||||
},
|
||||
tokenIcon: {
|
||||
width: 60,
|
||||
height: 60,
|
||||
alignSelf: 'center',
|
||||
marginTop: Spacing.md,
|
||||
},
|
||||
title: {
|
||||
fontSize: Typography.sizes.xxl,
|
||||
fontWeight: Typography.weights.bold,
|
||||
color: Colors.textDark,
|
||||
textAlign: 'center',
|
||||
marginTop: Spacing.sm,
|
||||
marginBottom: Spacing.lg,
|
||||
},
|
||||
qrCard: {
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: BorderRadius.lg,
|
||||
padding: Spacing.lg,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
...Shadow.small,
|
||||
alignSelf: 'center',
|
||||
},
|
||||
addressContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: Colors.background,
|
||||
borderRadius: BorderRadius.md,
|
||||
paddingHorizontal: Spacing.md,
|
||||
paddingVertical: Spacing.sm,
|
||||
marginTop: Spacing.lg,
|
||||
},
|
||||
addressText: {
|
||||
fontSize: Typography.sizes.sm,
|
||||
fontFamily: 'monospace',
|
||||
color: Colors.textDark,
|
||||
marginRight: Spacing.sm,
|
||||
},
|
||||
tapToCopy: {
|
||||
fontSize: Typography.sizes.xs,
|
||||
color: Colors.textLight,
|
||||
textAlign: 'center',
|
||||
marginTop: Spacing.xs,
|
||||
},
|
||||
networkBadge: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: '#E3F2FD',
|
||||
borderRadius: BorderRadius.md,
|
||||
paddingHorizontal: Spacing.md,
|
||||
paddingVertical: Spacing.sm,
|
||||
marginTop: Spacing.lg,
|
||||
alignSelf: 'center',
|
||||
},
|
||||
networkText: {
|
||||
fontSize: Typography.sizes.md,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: '#007AFF',
|
||||
marginLeft: Spacing.xs,
|
||||
},
|
||||
shareButton: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: Colors.background,
|
||||
borderRadius: BorderRadius.md,
|
||||
paddingVertical: Spacing.md,
|
||||
marginTop: Spacing.lg,
|
||||
},
|
||||
shareButtonText: {
|
||||
fontSize: Typography.sizes.md,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.textDark,
|
||||
marginLeft: Spacing.sm,
|
||||
},
|
||||
warningBox: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#FEF3C7',
|
||||
borderRadius: BorderRadius.md,
|
||||
padding: Spacing.md,
|
||||
marginTop: Spacing.lg,
|
||||
},
|
||||
warningText: {
|
||||
flex: 1,
|
||||
fontSize: Typography.sizes.sm,
|
||||
color: '#92400E',
|
||||
marginLeft: Spacing.sm,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,300 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
Modal,
|
||||
TouchableOpacity,
|
||||
TextInput,
|
||||
Image,
|
||||
Alert,
|
||||
} from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import Colors from '../constants/colors';
|
||||
import { Typography, Spacing, BorderRadius, Shadow } from '../constants/theme';
|
||||
|
||||
interface SendModalProps {
|
||||
visible: boolean;
|
||||
onClose: () => void;
|
||||
token: {
|
||||
symbol: string;
|
||||
name: string;
|
||||
balance: string;
|
||||
icon: any;
|
||||
color: string;
|
||||
};
|
||||
}
|
||||
|
||||
export default function SendModal({ visible, onClose, token }: SendModalProps) {
|
||||
const [recipientAddress, setRecipientAddress] = useState('');
|
||||
const [amount, setAmount] = useState('');
|
||||
const [network, setNetwork] = useState('Optimism');
|
||||
|
||||
const handleMaxAmount = () => {
|
||||
setAmount(token.balance);
|
||||
};
|
||||
|
||||
const handleSend = () => {
|
||||
if (!recipientAddress) {
|
||||
Alert.alert('Error', 'Please enter recipient address');
|
||||
return;
|
||||
}
|
||||
if (!amount || parseFloat(amount) <= 0) {
|
||||
Alert.alert('Error', 'Please enter valid amount');
|
||||
return;
|
||||
}
|
||||
if (parseFloat(amount) > parseFloat(token.balance)) {
|
||||
Alert.alert('Error', 'Insufficient balance');
|
||||
return;
|
||||
}
|
||||
|
||||
Alert.alert(
|
||||
'Confirm Transaction',
|
||||
`Send ${amount} ${token.symbol} to ${recipientAddress.substring(0, 10)}...?`,
|
||||
[
|
||||
{ text: 'Cancel', style: 'cancel' },
|
||||
{
|
||||
text: 'Confirm',
|
||||
onPress: () => {
|
||||
// TODO: Integrate with blockchain service
|
||||
Alert.alert('Success', 'Transaction submitted!');
|
||||
onClose();
|
||||
setRecipientAddress('');
|
||||
setAmount('');
|
||||
},
|
||||
},
|
||||
]
|
||||
);
|
||||
};
|
||||
|
||||
const handleQRScan = () => {
|
||||
// TODO: Open QR scanner
|
||||
Alert.alert('QR Scanner', 'QR scanner will be implemented');
|
||||
};
|
||||
|
||||
const handlePaste = async () => {
|
||||
// TODO: Paste from clipboard
|
||||
Alert.alert('Paste', 'Clipboard paste will be implemented');
|
||||
};
|
||||
|
||||
const usdValue = (parseFloat(amount) || 0) * 1.5; // Mock exchange rate
|
||||
|
||||
return (
|
||||
<Modal
|
||||
visible={visible}
|
||||
transparent
|
||||
animationType="slide"
|
||||
onRequestClose={onClose}
|
||||
>
|
||||
<View style={styles.overlay}>
|
||||
<View style={styles.modalContainer}>
|
||||
{/* Close Button */}
|
||||
<TouchableOpacity style={styles.closeButton} onPress={onClose}>
|
||||
<Ionicons name="close" size={28} color={Colors.textDark} />
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* Token Icon */}
|
||||
<Image source={token.icon} style={styles.tokenIcon} />
|
||||
|
||||
{/* Title */}
|
||||
<Text style={styles.title}>Send {token.symbol}</Text>
|
||||
|
||||
{/* Available Balance */}
|
||||
<Text style={styles.balance}>
|
||||
Available Balance: {token.balance} {token.symbol}
|
||||
</Text>
|
||||
|
||||
{/* Recipient Address */}
|
||||
<Text style={styles.label}>Recipient Address</Text>
|
||||
<View style={styles.inputContainer}>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Enter wallet address"
|
||||
placeholderTextColor={Colors.textLight}
|
||||
value={recipientAddress}
|
||||
onChangeText={setRecipientAddress}
|
||||
autoCapitalize="none"
|
||||
/>
|
||||
<TouchableOpacity style={styles.iconButton} onPress={handleQRScan}>
|
||||
<Ionicons name="qr-code-outline" size={24} color={Colors.primary} />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={styles.iconButton} onPress={handlePaste}>
|
||||
<Ionicons name="clipboard-outline" size={24} color={Colors.primary} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Amount */}
|
||||
<Text style={styles.label}>Amount</Text>
|
||||
<View style={styles.inputContainer}>
|
||||
<TextInput
|
||||
style={[styles.input, { flex: 1 }]}
|
||||
placeholder="0.00"
|
||||
placeholderTextColor={Colors.textLight}
|
||||
value={amount}
|
||||
onChangeText={setAmount}
|
||||
keyboardType="decimal-pad"
|
||||
/>
|
||||
<TouchableOpacity style={styles.maxButton} onPress={handleMaxAmount}>
|
||||
<Text style={styles.maxButtonText}>MAX</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<Text style={styles.usdValue}>USD Value: ${usdValue.toFixed(2)}</Text>
|
||||
|
||||
{/* Network */}
|
||||
<View style={styles.networkRow}>
|
||||
<Text style={styles.networkLabel}>Network:</Text>
|
||||
<TouchableOpacity style={styles.networkSelector}>
|
||||
<Text style={styles.networkText}>{network}</Text>
|
||||
<Ionicons name="chevron-down" size={20} color={Colors.textDark} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Transaction Fee */}
|
||||
<View style={styles.feeRow}>
|
||||
<Text style={styles.feeText}>Fee: 0.001 HEZ (~$0.01)</Text>
|
||||
</View>
|
||||
|
||||
{/* Send Button */}
|
||||
<TouchableOpacity
|
||||
style={[styles.sendButton, { backgroundColor: token.color }]}
|
||||
onPress={handleSend}
|
||||
>
|
||||
<Text style={styles.sendButtonText}>Send {token.symbol}</Text>
|
||||
<Ionicons name="arrow-forward" size={20} color="#FFFFFF" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
overlay: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: Spacing.lg,
|
||||
},
|
||||
modalContainer: {
|
||||
width: '100%',
|
||||
maxWidth: 400,
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: BorderRadius.xl,
|
||||
padding: Spacing.xl,
|
||||
...Shadow.medium,
|
||||
},
|
||||
closeButton: {
|
||||
position: 'absolute',
|
||||
top: Spacing.md,
|
||||
left: Spacing.md,
|
||||
zIndex: 1,
|
||||
},
|
||||
tokenIcon: {
|
||||
width: 60,
|
||||
height: 60,
|
||||
alignSelf: 'center',
|
||||
marginTop: Spacing.md,
|
||||
},
|
||||
title: {
|
||||
fontSize: Typography.sizes.xxl,
|
||||
fontWeight: Typography.weights.bold,
|
||||
color: Colors.textDark,
|
||||
textAlign: 'center',
|
||||
marginTop: Spacing.sm,
|
||||
},
|
||||
balance: {
|
||||
fontSize: Typography.sizes.md,
|
||||
color: Colors.textLight,
|
||||
textAlign: 'center',
|
||||
marginTop: Spacing.xs,
|
||||
marginBottom: Spacing.lg,
|
||||
},
|
||||
label: {
|
||||
fontSize: Typography.sizes.md,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.textDark,
|
||||
marginBottom: Spacing.xs,
|
||||
marginTop: Spacing.md,
|
||||
},
|
||||
inputContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: Colors.background,
|
||||
borderRadius: BorderRadius.md,
|
||||
paddingHorizontal: Spacing.md,
|
||||
paddingVertical: Spacing.sm,
|
||||
},
|
||||
input: {
|
||||
flex: 1,
|
||||
fontSize: Typography.sizes.md,
|
||||
color: Colors.textDark,
|
||||
paddingVertical: Spacing.xs,
|
||||
},
|
||||
iconButton: {
|
||||
marginLeft: Spacing.sm,
|
||||
},
|
||||
maxButton: {
|
||||
backgroundColor: Colors.primary,
|
||||
paddingHorizontal: Spacing.md,
|
||||
paddingVertical: Spacing.xs,
|
||||
borderRadius: BorderRadius.sm,
|
||||
},
|
||||
maxButtonText: {
|
||||
fontSize: Typography.sizes.sm,
|
||||
fontWeight: Typography.weights.bold,
|
||||
color: '#FFFFFF',
|
||||
},
|
||||
usdValue: {
|
||||
fontSize: Typography.sizes.sm,
|
||||
color: Colors.textLight,
|
||||
marginTop: Spacing.xs,
|
||||
},
|
||||
networkRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
marginTop: Spacing.lg,
|
||||
},
|
||||
networkLabel: {
|
||||
fontSize: Typography.sizes.md,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.textDark,
|
||||
},
|
||||
networkSelector: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: Colors.background,
|
||||
paddingHorizontal: Spacing.md,
|
||||
paddingVertical: Spacing.sm,
|
||||
borderRadius: BorderRadius.sm,
|
||||
},
|
||||
networkText: {
|
||||
fontSize: Typography.sizes.md,
|
||||
color: Colors.textDark,
|
||||
marginRight: Spacing.xs,
|
||||
},
|
||||
feeRow: {
|
||||
marginTop: Spacing.md,
|
||||
},
|
||||
feeText: {
|
||||
fontSize: Typography.sizes.sm,
|
||||
color: Colors.textLight,
|
||||
},
|
||||
sendButton: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingVertical: Spacing.md,
|
||||
borderRadius: BorderRadius.lg,
|
||||
marginTop: Spacing.xl,
|
||||
...Shadow.small,
|
||||
},
|
||||
sendButtonText: {
|
||||
fontSize: Typography.sizes.lg,
|
||||
fontWeight: Typography.weights.bold,
|
||||
color: '#FFFFFF',
|
||||
marginRight: Spacing.sm,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user