mirror of
https://github.com/pezkuwichain/pezkuwi-mobile-app.git
synced 2026-07-13 08:05:44 +00:00
auto-commit for df8d9453-f8cb-435f-b249-aff25371851c
This commit is contained in:
@@ -1,199 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
SafeAreaView,
|
||||
StatusBar,
|
||||
} from 'react-native';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import Colors from '../../constants/colors';
|
||||
import { Typography, Spacing, BorderRadius } from '../../constants/theme';
|
||||
|
||||
interface Language {
|
||||
code: string;
|
||||
name: string;
|
||||
nativeName: string;
|
||||
}
|
||||
|
||||
const LANGUAGES: Language[] = [
|
||||
{ code: 'en', name: 'English', nativeName: 'English' },
|
||||
{ code: 'ku', name: 'Kurdish (Kurmanji)', nativeName: 'Kurdî (Kurmancî)' },
|
||||
{ code: 'ckb', name: 'Kurdish (Sorani)', nativeName: 'کوردی (سۆرانی)' },
|
||||
{ code: 'tr', name: 'Turkish', nativeName: 'Türkçe' },
|
||||
{ code: 'ar', name: 'Arabic', nativeName: 'العربية' },
|
||||
{ code: 'fa', name: 'Persian', nativeName: 'فارسی' },
|
||||
];
|
||||
|
||||
export default function LanguageSelectionScreen({ navigation }: any) {
|
||||
const [selectedLanguage, setSelectedLanguage] = useState<string>('en');
|
||||
|
||||
const handleContinue = () => {
|
||||
// Save language preference
|
||||
// TODO: Implement i18n language switching
|
||||
navigation.navigate('WalletSetup');
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<StatusBar barStyle="light-content" />
|
||||
<LinearGradient
|
||||
colors={['#F08080', '#F5B895', '#E8C896']}
|
||||
style={styles.gradient}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 0, y: 1 }}
|
||||
>
|
||||
<View style={styles.content}>
|
||||
{/* Header */}
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.title}>Welcome to</Text>
|
||||
<Text style={styles.brandName}>PezkuwiChain</Text>
|
||||
<Text style={styles.subtitle}>Your Digital Citizenship Platform</Text>
|
||||
<Text style={styles.description}>
|
||||
Building the future of Kurdish digital infrastructure
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* Language Selection */}
|
||||
<View style={styles.languageSection}>
|
||||
<Text style={styles.sectionTitle}>Select Your Language</Text>
|
||||
|
||||
<View style={styles.languageGrid}>
|
||||
{LANGUAGES.map((language) => (
|
||||
<TouchableOpacity
|
||||
key={language.code}
|
||||
style={[
|
||||
styles.languageButton,
|
||||
selectedLanguage === language.code && styles.languageButtonSelected,
|
||||
]}
|
||||
onPress={() => setSelectedLanguage(language.code)}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
styles.languageText,
|
||||
selectedLanguage === language.code && styles.languageTextSelected,
|
||||
]}
|
||||
>
|
||||
{language.nativeName}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Continue Button */}
|
||||
<TouchableOpacity
|
||||
style={styles.continueButton}
|
||||
onPress={handleContinue}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
<Text style={styles.continueButtonText}>Get Started →</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.coral,
|
||||
},
|
||||
gradient: {
|
||||
flex: 1,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
paddingHorizontal: Spacing.xl,
|
||||
paddingVertical: Spacing.xxxl,
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
header: {
|
||||
alignItems: 'center',
|
||||
marginTop: Spacing.xxxl,
|
||||
},
|
||||
title: {
|
||||
fontSize: Typography.sizes.heading,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: '#FFFFFF',
|
||||
marginBottom: Spacing.sm,
|
||||
},
|
||||
brandName: {
|
||||
fontSize: Typography.sizes.display,
|
||||
fontWeight: Typography.weights.bold,
|
||||
color: '#FFFFFF',
|
||||
marginBottom: Spacing.md,
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: Typography.sizes.medium,
|
||||
fontWeight: Typography.weights.medium,
|
||||
color: '#FFFFFF',
|
||||
marginBottom: Spacing.sm,
|
||||
},
|
||||
description: {
|
||||
fontSize: Typography.sizes.body,
|
||||
color: 'rgba(255, 255, 255, 0.9)',
|
||||
textAlign: 'center',
|
||||
},
|
||||
languageSection: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: Typography.sizes.large,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: '#FFFFFF',
|
||||
textAlign: 'center',
|
||||
marginBottom: Spacing.xl,
|
||||
},
|
||||
languageGrid: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'space-between',
|
||||
gap: Spacing.md,
|
||||
},
|
||||
languageButton: {
|
||||
width: '48%',
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.2)',
|
||||
borderRadius: BorderRadius.large,
|
||||
paddingVertical: Spacing.lg,
|
||||
paddingHorizontal: Spacing.md,
|
||||
borderWidth: 2,
|
||||
borderColor: 'transparent',
|
||||
},
|
||||
languageButtonSelected: {
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.95)',
|
||||
borderColor: '#FFFFFF',
|
||||
},
|
||||
languageText: {
|
||||
fontSize: Typography.sizes.medium,
|
||||
fontWeight: Typography.weights.medium,
|
||||
color: '#FFFFFF',
|
||||
textAlign: 'center',
|
||||
},
|
||||
languageTextSelected: {
|
||||
color: Colors.coral,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
},
|
||||
continueButton: {
|
||||
backgroundColor: 'rgba(212, 160, 23, 0.9)',
|
||||
borderRadius: BorderRadius.xxlarge,
|
||||
paddingVertical: Spacing.lg,
|
||||
paddingHorizontal: Spacing.xxxl,
|
||||
alignItems: 'center',
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 4 },
|
||||
shadowOpacity: 0.2,
|
||||
shadowRadius: 8,
|
||||
elevation: 5,
|
||||
},
|
||||
continueButtonText: {
|
||||
fontSize: Typography.sizes.large,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: '#FFFFFF',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,326 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
SafeAreaView,
|
||||
KeyboardAvoidingView,
|
||||
Platform,
|
||||
ScrollView,
|
||||
} from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import Colors from '../../constants/colors';
|
||||
import { Typography, Spacing, BorderRadius, Shadow } from '../../constants/theme';
|
||||
|
||||
export default function SignUpScreen({ navigation }: any) {
|
||||
const [isSignUp, setIsSignUp] = useState(true);
|
||||
const [formData, setFormData] = useState({
|
||||
fullName: '',
|
||||
email: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
referralCode: '',
|
||||
});
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
|
||||
|
||||
const handleSubmit = () => {
|
||||
// TODO: Implement authentication logic
|
||||
navigation.navigate('MainTabs');
|
||||
};
|
||||
|
||||
const toggleMode = () => {
|
||||
setIsSignUp(!isSignUp);
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<KeyboardAvoidingView
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
style={styles.keyboardView}
|
||||
>
|
||||
<ScrollView
|
||||
contentContainerStyle={styles.scrollContent}
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
{/* Header */}
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.logo}>PezkuwiChain</Text>
|
||||
<Text style={styles.subtitle}>Access your governance account</Text>
|
||||
</View>
|
||||
|
||||
{/* Toggle Buttons */}
|
||||
<View style={styles.toggleContainer}>
|
||||
<TouchableOpacity
|
||||
style={[styles.toggleButton, !isSignUp && styles.toggleButtonActive]}
|
||||
onPress={() => setIsSignUp(false)}
|
||||
>
|
||||
<Text style={[styles.toggleText, !isSignUp && styles.toggleTextActive]}>
|
||||
Sign In
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[styles.toggleButton, isSignUp && styles.toggleButtonActive]}
|
||||
onPress={() => setIsSignUp(true)}
|
||||
>
|
||||
<Text style={[styles.toggleText, isSignUp && styles.toggleTextActive]}>
|
||||
Sign Up
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Form */}
|
||||
<View style={styles.form}>
|
||||
{isSignUp && (
|
||||
<View style={styles.inputContainer}>
|
||||
<Text style={styles.label}>Full Name</Text>
|
||||
<View style={styles.inputWrapper}>
|
||||
<Ionicons name="person-outline" size={20} color={Colors.textGray} />
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="John Doe"
|
||||
placeholderTextColor={Colors.textLight}
|
||||
value={formData.fullName}
|
||||
onChangeText={(text) => setFormData({ ...formData, fullName: text })}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
<View style={styles.inputContainer}>
|
||||
<Text style={styles.label}>Email</Text>
|
||||
<View style={styles.inputWrapper}>
|
||||
<Ionicons name="mail-outline" size={20} color={Colors.textGray} />
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="name@example.com"
|
||||
placeholderTextColor={Colors.textLight}
|
||||
keyboardType="email-address"
|
||||
autoCapitalize="none"
|
||||
value={formData.email}
|
||||
onChangeText={(text) => setFormData({ ...formData, email: text })}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.inputContainer}>
|
||||
<Text style={styles.label}>Password</Text>
|
||||
<View style={styles.inputWrapper}>
|
||||
<Ionicons name="lock-closed-outline" size={20} color={Colors.textGray} />
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="••••••••"
|
||||
placeholderTextColor={Colors.textLight}
|
||||
secureTextEntry={!showPassword}
|
||||
value={formData.password}
|
||||
onChangeText={(text) => setFormData({ ...formData, password: text })}
|
||||
/>
|
||||
<TouchableOpacity onPress={() => setShowPassword(!showPassword)}>
|
||||
<Ionicons
|
||||
name={showPassword ? 'eye-outline' : 'eye-off-outline'}
|
||||
size={20}
|
||||
color={Colors.textGray}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{isSignUp && (
|
||||
<>
|
||||
<View style={styles.inputContainer}>
|
||||
<Text style={styles.label}>Confirm Password</Text>
|
||||
<View style={styles.inputWrapper}>
|
||||
<Ionicons name="lock-closed-outline" size={20} color={Colors.textGray} />
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="••••••••"
|
||||
placeholderTextColor={Colors.textLight}
|
||||
secureTextEntry={!showConfirmPassword}
|
||||
value={formData.confirmPassword}
|
||||
onChangeText={(text) =>
|
||||
setFormData({ ...formData, confirmPassword: text })
|
||||
}
|
||||
/>
|
||||
<TouchableOpacity
|
||||
onPress={() => setShowConfirmPassword(!showConfirmPassword)}
|
||||
>
|
||||
<Ionicons
|
||||
name={showConfirmPassword ? 'eye-outline' : 'eye-off-outline'}
|
||||
size={20}
|
||||
color={Colors.textGray}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.inputContainer}>
|
||||
<Text style={styles.label}>Referral Code (Optional)</Text>
|
||||
<View style={styles.inputWrapper}>
|
||||
<Ionicons name="gift-outline" size={20} color={Colors.textGray} />
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Enter referral code"
|
||||
placeholderTextColor={Colors.textLight}
|
||||
autoCapitalize="characters"
|
||||
value={formData.referralCode}
|
||||
onChangeText={(text) =>
|
||||
setFormData({ ...formData, referralCode: text })
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
|
||||
{!isSignUp && (
|
||||
<TouchableOpacity style={styles.forgotPassword}>
|
||||
<Text style={styles.forgotPasswordText}>Forgot Password?</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
||||
{/* Submit Button */}
|
||||
<TouchableOpacity style={styles.submitButton} onPress={handleSubmit}>
|
||||
<Text style={styles.submitButtonText}>
|
||||
{isSignUp ? 'Create Account' : 'Sign In'}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* Footer */}
|
||||
<View style={styles.footer}>
|
||||
<Text style={styles.footerText}>
|
||||
{isSignUp ? 'Already have an account?' : "Don't have an account?"}
|
||||
</Text>
|
||||
<TouchableOpacity onPress={toggleMode}>
|
||||
<Text style={styles.footerLink}>
|
||||
{isSignUp ? 'Sign In' : 'Sign Up'}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</KeyboardAvoidingView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.navy,
|
||||
},
|
||||
keyboardView: {
|
||||
flex: 1,
|
||||
},
|
||||
scrollContent: {
|
||||
flexGrow: 1,
|
||||
paddingHorizontal: Spacing.xl,
|
||||
paddingVertical: Spacing.xxxl,
|
||||
},
|
||||
header: {
|
||||
alignItems: 'center',
|
||||
marginBottom: Spacing.xxxl,
|
||||
},
|
||||
logo: {
|
||||
fontSize: Typography.sizes.display,
|
||||
fontWeight: Typography.weights.bold,
|
||||
color: Colors.mint,
|
||||
marginBottom: Spacing.sm,
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: Typography.sizes.medium,
|
||||
color: Colors.textLight,
|
||||
},
|
||||
toggleContainer: {
|
||||
flexDirection: 'row',
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
||||
borderRadius: BorderRadius.large,
|
||||
padding: Spacing.xs,
|
||||
marginBottom: Spacing.xl,
|
||||
},
|
||||
toggleButton: {
|
||||
flex: 1,
|
||||
paddingVertical: Spacing.md,
|
||||
alignItems: 'center',
|
||||
borderRadius: BorderRadius.medium,
|
||||
},
|
||||
toggleButtonActive: {
|
||||
backgroundColor: Colors.mint,
|
||||
},
|
||||
toggleText: {
|
||||
fontSize: Typography.sizes.medium,
|
||||
fontWeight: Typography.weights.medium,
|
||||
color: Colors.textLight,
|
||||
},
|
||||
toggleTextActive: {
|
||||
color: Colors.navy,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
},
|
||||
form: {
|
||||
flex: 1,
|
||||
},
|
||||
inputContainer: {
|
||||
marginBottom: Spacing.lg,
|
||||
},
|
||||
label: {
|
||||
fontSize: Typography.sizes.body,
|
||||
fontWeight: Typography.weights.medium,
|
||||
color: '#FFFFFF',
|
||||
marginBottom: Spacing.sm,
|
||||
},
|
||||
inputWrapper: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
||||
borderRadius: BorderRadius.medium,
|
||||
paddingHorizontal: Spacing.md,
|
||||
paddingVertical: Spacing.sm,
|
||||
borderWidth: 1,
|
||||
borderColor: 'rgba(255, 255, 255, 0.2)',
|
||||
},
|
||||
input: {
|
||||
flex: 1,
|
||||
fontSize: Typography.sizes.medium,
|
||||
color: '#FFFFFF',
|
||||
marginLeft: Spacing.sm,
|
||||
},
|
||||
forgotPassword: {
|
||||
alignSelf: 'flex-end',
|
||||
marginBottom: Spacing.lg,
|
||||
},
|
||||
forgotPasswordText: {
|
||||
fontSize: Typography.sizes.small,
|
||||
color: Colors.mint,
|
||||
},
|
||||
submitButton: {
|
||||
backgroundColor: Colors.peach,
|
||||
borderRadius: BorderRadius.xxlarge,
|
||||
paddingVertical: Spacing.lg,
|
||||
alignItems: 'center',
|
||||
marginTop: Spacing.lg,
|
||||
...Shadow.soft,
|
||||
},
|
||||
submitButtonText: {
|
||||
fontSize: Typography.sizes.large,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: '#FFFFFF',
|
||||
},
|
||||
footer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginTop: Spacing.xl,
|
||||
gap: Spacing.xs,
|
||||
},
|
||||
footerText: {
|
||||
fontSize: Typography.sizes.body,
|
||||
color: Colors.textLight,
|
||||
},
|
||||
footerLink: {
|
||||
fontSize: Typography.sizes.body,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.mint,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,794 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
TextInput,
|
||||
Modal,
|
||||
Alert,
|
||||
} from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import QRCode from 'react-native-qrcode-svg';
|
||||
import * as Clipboard from 'expo-clipboard';
|
||||
import Colors from '../../constants/colors';
|
||||
|
||||
interface BusinessStats {
|
||||
totalSales: number;
|
||||
todaySales: number;
|
||||
pendingPayments: number;
|
||||
totalCustomers: number;
|
||||
}
|
||||
|
||||
interface Transaction {
|
||||
id: string;
|
||||
customer: string;
|
||||
amount: number;
|
||||
token: 'HEZ' | 'PEZ';
|
||||
date: string;
|
||||
status: 'completed' | 'pending' | 'failed';
|
||||
invoiceId: string;
|
||||
}
|
||||
|
||||
export default function BusinessScreen({ navigation }: any) {
|
||||
const [merchantAddress] = useState('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY');
|
||||
const [showPaymentModal, setShowPaymentModal] = useState(false);
|
||||
const [paymentAmount, setPaymentAmount] = useState('');
|
||||
const [selectedToken, setSelectedToken] = useState<'HEZ' | 'PEZ'>('PEZ');
|
||||
const [paymentNote, setPaymentNote] = useState('');
|
||||
|
||||
const [stats] = useState<BusinessStats>({
|
||||
totalSales: 125450,
|
||||
todaySales: 3250,
|
||||
pendingPayments: 850,
|
||||
totalCustomers: 342,
|
||||
});
|
||||
|
||||
const [transactions] = useState<Transaction[]>([
|
||||
{
|
||||
id: '1',
|
||||
customer: 'Ahmed Karwan',
|
||||
amount: 500,
|
||||
token: 'PEZ',
|
||||
date: '2024-01-23 14:30',
|
||||
status: 'completed',
|
||||
invoiceId: 'INV-2024-001',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
customer: 'Layla Sherzad',
|
||||
amount: 1250,
|
||||
token: 'HEZ',
|
||||
date: '2024-01-23 12:15',
|
||||
status: 'completed',
|
||||
invoiceId: 'INV-2024-002',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
customer: 'Saman Aziz',
|
||||
amount: 750,
|
||||
token: 'PEZ',
|
||||
date: '2024-01-23 10:45',
|
||||
status: 'pending',
|
||||
invoiceId: 'INV-2024-003',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
customer: 'Hana Dilshad',
|
||||
amount: 350,
|
||||
token: 'PEZ',
|
||||
date: '2024-01-22 16:20',
|
||||
status: 'completed',
|
||||
invoiceId: 'INV-2024-004',
|
||||
},
|
||||
]);
|
||||
|
||||
const generatePaymentQR = () => {
|
||||
if (!paymentAmount || parseFloat(paymentAmount) <= 0) {
|
||||
Alert.alert('Invalid Amount', 'Please enter a valid payment amount');
|
||||
return;
|
||||
}
|
||||
setShowPaymentModal(true);
|
||||
};
|
||||
|
||||
const copyMerchantAddress = async () => {
|
||||
await Clipboard.setStringAsync(merchantAddress);
|
||||
Alert.alert('✓ Copied!', 'Merchant address copied to clipboard');
|
||||
};
|
||||
|
||||
const getStatusColor = (status: string) => {
|
||||
switch (status) {
|
||||
case 'completed':
|
||||
return Colors.success;
|
||||
case 'pending':
|
||||
return Colors.warning;
|
||||
case 'failed':
|
||||
return Colors.error;
|
||||
default:
|
||||
return Colors.textGray;
|
||||
}
|
||||
};
|
||||
|
||||
const paymentData = JSON.stringify({
|
||||
merchant: merchantAddress,
|
||||
amount: paymentAmount,
|
||||
token: selectedToken,
|
||||
note: paymentNote,
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<ScrollView showsVerticalScrollIndicator={false}>
|
||||
{/* Header */}
|
||||
<LinearGradient
|
||||
colors={[Colors.kurdishGold, Colors.coral]}
|
||||
style={styles.header}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
>
|
||||
<View style={styles.headerContent}>
|
||||
<View>
|
||||
<Text style={styles.headerTitle}>Business Hub</Text>
|
||||
<Text style={styles.headerSubtitle}>Merchant Payment Center</Text>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
style={styles.settingsButton}
|
||||
onPress={() => Alert.alert('Settings', 'Business settings coming soon')}
|
||||
>
|
||||
<Ionicons name="settings-outline" size={24} color="white" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
|
||||
{/* Statistics Grid */}
|
||||
<View style={styles.statsContainer}>
|
||||
<View style={styles.statsGrid}>
|
||||
<View style={styles.statCard}>
|
||||
<Ionicons name="cash" size={28} color={Colors.success} />
|
||||
<Text style={styles.statValue}>{stats.totalSales.toLocaleString()}</Text>
|
||||
<Text style={styles.statLabel}>Total Sales (PEZ)</Text>
|
||||
</View>
|
||||
<View style={styles.statCard}>
|
||||
<Ionicons name="trending-up" size={28} color={Colors.primary} />
|
||||
<Text style={styles.statValue}>{stats.todaySales.toLocaleString()}</Text>
|
||||
<Text style={styles.statLabel}>Today's Sales</Text>
|
||||
</View>
|
||||
<View style={styles.statCard}>
|
||||
<Ionicons name="time" size={28} color={Colors.warning} />
|
||||
<Text style={styles.statValue}>{stats.pendingPayments.toLocaleString()}</Text>
|
||||
<Text style={styles.statLabel}>Pending</Text>
|
||||
</View>
|
||||
<View style={styles.statCard}>
|
||||
<Ionicons name="people" size={28} color={Colors.kurdishGold} />
|
||||
<Text style={styles.statValue}>{stats.totalCustomers}</Text>
|
||||
<Text style={styles.statLabel}>Customers</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Quick Actions */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Quick Actions</Text>
|
||||
<View style={styles.actionsGrid}>
|
||||
<TouchableOpacity style={styles.actionCard} activeOpacity={0.7}>
|
||||
<View style={[styles.actionIcon, { backgroundColor: Colors.primary + '20' }]}>
|
||||
<Ionicons name="qr-code" size={32} color={Colors.primary} />
|
||||
</View>
|
||||
<Text style={styles.actionLabel}>Generate QR</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={styles.actionCard} activeOpacity={0.7}>
|
||||
<View style={[styles.actionIcon, { backgroundColor: Colors.success + '20' }]}>
|
||||
<Ionicons name="document-text" size={32} color={Colors.success} />
|
||||
</View>
|
||||
<Text style={styles.actionLabel}>Create Invoice</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={styles.actionCard} activeOpacity={0.7}>
|
||||
<View style={[styles.actionIcon, { backgroundColor: Colors.kurdishGold + '20' }]}>
|
||||
<Ionicons name="stats-chart" size={32} color={Colors.kurdishGold} />
|
||||
</View>
|
||||
<Text style={styles.actionLabel}>Analytics</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={styles.actionCard} activeOpacity={0.7}>
|
||||
<View style={[styles.actionIcon, { backgroundColor: Colors.coral + '20' }]}>
|
||||
<Ionicons name="card" size={32} color={Colors.coral} />
|
||||
</View>
|
||||
<Text style={styles.actionLabel}>Payment Link</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Payment Request Form */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Create Payment Request</Text>
|
||||
<View style={styles.formCard}>
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.inputLabel}>Amount</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Enter amount"
|
||||
keyboardType="decimal-pad"
|
||||
value={paymentAmount}
|
||||
onChangeText={setPaymentAmount}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.inputLabel}>Token</Text>
|
||||
<View style={styles.tokenSelector}>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.tokenOption,
|
||||
selectedToken === 'PEZ' && styles.tokenOptionActive,
|
||||
]}
|
||||
onPress={() => setSelectedToken('PEZ')}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
styles.tokenOptionText,
|
||||
selectedToken === 'PEZ' && styles.tokenOptionTextActive,
|
||||
]}
|
||||
>
|
||||
PEZ
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.tokenOption,
|
||||
selectedToken === 'HEZ' && styles.tokenOptionActive,
|
||||
]}
|
||||
onPress={() => setSelectedToken('HEZ')}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
styles.tokenOptionText,
|
||||
selectedToken === 'HEZ' && styles.tokenOptionTextActive,
|
||||
]}
|
||||
>
|
||||
HEZ
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.inputLabel}>Note (Optional)</Text>
|
||||
<TextInput
|
||||
style={[styles.input, styles.textArea]}
|
||||
placeholder="Payment description"
|
||||
multiline
|
||||
numberOfLines={3}
|
||||
value={paymentNote}
|
||||
onChangeText={setPaymentNote}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.generateButton}
|
||||
onPress={generatePaymentQR}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={[Colors.primary, Colors.success]}
|
||||
style={styles.generateButtonGradient}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 0 }}
|
||||
>
|
||||
<Ionicons name="qr-code" size={20} color="white" />
|
||||
<Text style={styles.generateButtonText}>Generate Payment QR</Text>
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Recent Transactions */}
|
||||
<View style={styles.section}>
|
||||
<View style={styles.sectionHeader}>
|
||||
<Text style={styles.sectionTitle}>Recent Transactions</Text>
|
||||
<TouchableOpacity>
|
||||
<Text style={styles.viewAllText}>View All</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{transactions.map((transaction) => (
|
||||
<View key={transaction.id} style={styles.transactionCard}>
|
||||
<View style={styles.transactionHeader}>
|
||||
<View style={styles.transactionIcon}>
|
||||
<Ionicons
|
||||
name={
|
||||
transaction.status === 'completed'
|
||||
? 'checkmark-circle'
|
||||
: transaction.status === 'pending'
|
||||
? 'time'
|
||||
: 'close-circle'
|
||||
}
|
||||
size={24}
|
||||
color={getStatusColor(transaction.status)}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.transactionInfo}>
|
||||
<Text style={styles.transactionCustomer}>
|
||||
{transaction.customer}
|
||||
</Text>
|
||||
<Text style={styles.transactionDate}>{transaction.date}</Text>
|
||||
<Text style={styles.transactionInvoice}>
|
||||
{transaction.invoiceId}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.transactionAmount}>
|
||||
<Text style={styles.amountValue}>
|
||||
{transaction.amount.toLocaleString()}
|
||||
</Text>
|
||||
<Text style={styles.amountToken}>{transaction.token}</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View
|
||||
style={[
|
||||
styles.statusBadge,
|
||||
{ backgroundColor: getStatusColor(transaction.status) + '20' },
|
||||
]}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
styles.statusText,
|
||||
{ color: getStatusColor(transaction.status) },
|
||||
]}
|
||||
>
|
||||
{transaction.status.charAt(0).toUpperCase() +
|
||||
transaction.status.slice(1)}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
|
||||
{/* Merchant Info */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Merchant Information</Text>
|
||||
<View style={styles.merchantCard}>
|
||||
<View style={styles.merchantHeader}>
|
||||
<Ionicons name="storefront" size={24} color={Colors.primary} />
|
||||
<Text style={styles.merchantTitle}>Your Merchant Address</Text>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
style={styles.addressBox}
|
||||
onPress={copyMerchantAddress}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Text style={styles.addressText} numberOfLines={1}>
|
||||
{merchantAddress}
|
||||
</Text>
|
||||
<Ionicons name="copy-outline" size={20} color={Colors.primary} />
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.merchantNote}>
|
||||
Share this address with customers to receive payments
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={{ height: 40 }} />
|
||||
</ScrollView>
|
||||
|
||||
{/* Payment QR Modal */}
|
||||
<Modal
|
||||
visible={showPaymentModal}
|
||||
transparent
|
||||
animationType="fade"
|
||||
onRequestClose={() => setShowPaymentModal(false)}
|
||||
>
|
||||
<View style={styles.modalOverlay}>
|
||||
<View style={styles.modalContent}>
|
||||
<View style={styles.modalHeader}>
|
||||
<Text style={styles.modalTitle}>Payment QR Code</Text>
|
||||
<TouchableOpacity onPress={() => setShowPaymentModal(false)}>
|
||||
<Ionicons name="close" size={28} color={Colors.textDark} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<View style={styles.qrContainer}>
|
||||
<QRCode value={paymentData} size={200} />
|
||||
</View>
|
||||
|
||||
<View style={styles.paymentDetails}>
|
||||
<View style={styles.paymentDetailRow}>
|
||||
<Text style={styles.paymentDetailLabel}>Amount:</Text>
|
||||
<Text style={styles.paymentDetailValue}>
|
||||
{paymentAmount} {selectedToken}
|
||||
</Text>
|
||||
</View>
|
||||
{paymentNote ? (
|
||||
<View style={styles.paymentDetailRow}>
|
||||
<Text style={styles.paymentDetailLabel}>Note:</Text>
|
||||
<Text style={styles.paymentDetailValue}>{paymentNote}</Text>
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
<Text style={styles.qrInstruction}>
|
||||
Ask customer to scan this QR code with their PezkuwiChain app
|
||||
</Text>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.doneButton}
|
||||
onPress={() => setShowPaymentModal(false)}
|
||||
>
|
||||
<Text style={styles.doneButtonText}>Done</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.background,
|
||||
},
|
||||
header: {
|
||||
paddingHorizontal: 20,
|
||||
paddingTop: 20,
|
||||
paddingBottom: 24,
|
||||
borderBottomLeftRadius: 24,
|
||||
borderBottomRightRadius: 24,
|
||||
},
|
||||
headerContent: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: 32,
|
||||
fontWeight: '700',
|
||||
color: 'white',
|
||||
marginBottom: 4,
|
||||
},
|
||||
headerSubtitle: {
|
||||
fontSize: 16,
|
||||
color: 'rgba(255, 255, 255, 0.9)',
|
||||
},
|
||||
settingsButton: {
|
||||
width: 48,
|
||||
height: 48,
|
||||
borderRadius: 24,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.2)',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
statsContainer: {
|
||||
paddingHorizontal: 20,
|
||||
marginTop: -30,
|
||||
marginBottom: 20,
|
||||
},
|
||||
statsGrid: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
gap: 12,
|
||||
},
|
||||
statCard: {
|
||||
flex: 1,
|
||||
minWidth: '47%',
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 14,
|
||||
padding: 16,
|
||||
alignItems: 'center',
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.05,
|
||||
shadowRadius: 8,
|
||||
elevation: 2,
|
||||
},
|
||||
statValue: {
|
||||
fontSize: 24,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
marginTop: 8,
|
||||
marginBottom: 4,
|
||||
},
|
||||
statLabel: {
|
||||
fontSize: 13,
|
||||
color: Colors.textGray,
|
||||
textAlign: 'center',
|
||||
},
|
||||
section: {
|
||||
paddingHorizontal: 20,
|
||||
marginBottom: 24,
|
||||
},
|
||||
sectionHeader: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 12,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 20,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
marginBottom: 12,
|
||||
},
|
||||
viewAllText: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: Colors.primary,
|
||||
},
|
||||
actionsGrid: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
gap: 12,
|
||||
},
|
||||
actionCard: {
|
||||
flex: 1,
|
||||
minWidth: '47%',
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 14,
|
||||
padding: 16,
|
||||
alignItems: 'center',
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.04,
|
||||
shadowRadius: 6,
|
||||
elevation: 1,
|
||||
},
|
||||
actionIcon: {
|
||||
width: 64,
|
||||
height: 64,
|
||||
borderRadius: 16,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginBottom: 12,
|
||||
},
|
||||
actionLabel: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: Colors.textDark,
|
||||
textAlign: 'center',
|
||||
},
|
||||
formCard: {
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 14,
|
||||
padding: 20,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.04,
|
||||
shadowRadius: 6,
|
||||
elevation: 1,
|
||||
},
|
||||
inputGroup: {
|
||||
marginBottom: 16,
|
||||
},
|
||||
inputLabel: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: Colors.textDark,
|
||||
marginBottom: 8,
|
||||
},
|
||||
input: {
|
||||
backgroundColor: Colors.background,
|
||||
borderRadius: 10,
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 12,
|
||||
fontSize: 15,
|
||||
color: Colors.textDark,
|
||||
},
|
||||
textArea: {
|
||||
height: 80,
|
||||
textAlignVertical: 'top',
|
||||
},
|
||||
tokenSelector: {
|
||||
flexDirection: 'row',
|
||||
gap: 12,
|
||||
},
|
||||
tokenOption: {
|
||||
flex: 1,
|
||||
paddingVertical: 12,
|
||||
borderRadius: 10,
|
||||
backgroundColor: Colors.background,
|
||||
alignItems: 'center',
|
||||
},
|
||||
tokenOptionActive: {
|
||||
backgroundColor: Colors.primary,
|
||||
},
|
||||
tokenOptionText: {
|
||||
fontSize: 15,
|
||||
fontWeight: '600',
|
||||
color: Colors.textGray,
|
||||
},
|
||||
tokenOptionTextActive: {
|
||||
color: 'white',
|
||||
},
|
||||
generateButton: {
|
||||
borderRadius: 10,
|
||||
overflow: 'hidden',
|
||||
marginTop: 8,
|
||||
},
|
||||
generateButtonGradient: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingVertical: 14,
|
||||
gap: 8,
|
||||
},
|
||||
generateButtonText: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: 'white',
|
||||
},
|
||||
transactionCard: {
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 14,
|
||||
padding: 16,
|
||||
marginBottom: 12,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.04,
|
||||
shadowRadius: 6,
|
||||
elevation: 1,
|
||||
},
|
||||
transactionHeader: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginBottom: 12,
|
||||
},
|
||||
transactionIcon: {
|
||||
marginRight: 12,
|
||||
},
|
||||
transactionInfo: {
|
||||
flex: 1,
|
||||
},
|
||||
transactionCustomer: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: Colors.textDark,
|
||||
marginBottom: 2,
|
||||
},
|
||||
transactionDate: {
|
||||
fontSize: 12,
|
||||
color: Colors.textGray,
|
||||
marginBottom: 2,
|
||||
},
|
||||
transactionInvoice: {
|
||||
fontSize: 11,
|
||||
color: Colors.textGray,
|
||||
fontFamily: 'monospace',
|
||||
},
|
||||
transactionAmount: {
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
amountValue: {
|
||||
fontSize: 18,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
},
|
||||
amountToken: {
|
||||
fontSize: 12,
|
||||
color: Colors.textGray,
|
||||
marginTop: 2,
|
||||
},
|
||||
statusBadge: {
|
||||
alignSelf: 'flex-start',
|
||||
paddingHorizontal: 10,
|
||||
paddingVertical: 4,
|
||||
borderRadius: 8,
|
||||
},
|
||||
statusText: {
|
||||
fontSize: 12,
|
||||
fontWeight: '600',
|
||||
},
|
||||
merchantCard: {
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 14,
|
||||
padding: 20,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.04,
|
||||
shadowRadius: 6,
|
||||
elevation: 1,
|
||||
},
|
||||
merchantHeader: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
marginBottom: 12,
|
||||
},
|
||||
merchantTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: Colors.textDark,
|
||||
},
|
||||
addressBox: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
backgroundColor: Colors.background,
|
||||
borderRadius: 10,
|
||||
padding: 12,
|
||||
marginBottom: 8,
|
||||
},
|
||||
addressText: {
|
||||
flex: 1,
|
||||
fontSize: 13,
|
||||
color: Colors.textDark,
|
||||
fontFamily: 'monospace',
|
||||
marginRight: 8,
|
||||
},
|
||||
merchantNote: {
|
||||
fontSize: 12,
|
||||
color: Colors.textGray,
|
||||
lineHeight: 18,
|
||||
},
|
||||
modalOverlay: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: 20,
|
||||
},
|
||||
modalContent: {
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 20,
|
||||
padding: 24,
|
||||
width: '100%',
|
||||
maxWidth: 400,
|
||||
},
|
||||
modalHeader: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 24,
|
||||
},
|
||||
modalTitle: {
|
||||
fontSize: 22,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
},
|
||||
qrContainer: {
|
||||
alignItems: 'center',
|
||||
padding: 20,
|
||||
backgroundColor: Colors.background,
|
||||
borderRadius: 16,
|
||||
marginBottom: 20,
|
||||
},
|
||||
paymentDetails: {
|
||||
backgroundColor: Colors.background,
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
marginBottom: 16,
|
||||
gap: 8,
|
||||
},
|
||||
paymentDetailRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
paymentDetailLabel: {
|
||||
fontSize: 14,
|
||||
color: Colors.textGray,
|
||||
},
|
||||
paymentDetailValue: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: Colors.textDark,
|
||||
},
|
||||
qrInstruction: {
|
||||
fontSize: 13,
|
||||
color: Colors.textGray,
|
||||
textAlign: 'center',
|
||||
marginBottom: 20,
|
||||
lineHeight: 20,
|
||||
},
|
||||
doneButton: {
|
||||
backgroundColor: Colors.primary,
|
||||
borderRadius: 10,
|
||||
paddingVertical: 14,
|
||||
alignItems: 'center',
|
||||
},
|
||||
doneButtonText: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: 'white',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,626 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
Share,
|
||||
Alert,
|
||||
} from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import Colors from '../../constants/colors';
|
||||
|
||||
interface Certificate {
|
||||
id: string;
|
||||
title: string;
|
||||
institution: string;
|
||||
issueDate: string;
|
||||
certificateId: string;
|
||||
type: 'degree' | 'course' | 'skill' | 'achievement';
|
||||
verified: boolean;
|
||||
ipfsHash?: string;
|
||||
}
|
||||
|
||||
interface EducationStats {
|
||||
totalCertificates: number;
|
||||
verifiedCertificates: number;
|
||||
skillsAcquired: number;
|
||||
learningHours: number;
|
||||
}
|
||||
|
||||
export default function EducationScreen({ navigation }: any) {
|
||||
const [stats] = useState<EducationStats>({
|
||||
totalCertificates: 8,
|
||||
verifiedCertificates: 6,
|
||||
skillsAcquired: 15,
|
||||
learningHours: 240,
|
||||
});
|
||||
|
||||
const [certificates] = useState<Certificate[]>([
|
||||
{
|
||||
id: '1',
|
||||
title: 'Bachelor of Computer Science',
|
||||
institution: 'University of Kurdistan',
|
||||
issueDate: '2022-06-15',
|
||||
certificateId: 'UOK-CS-2022-1234',
|
||||
type: 'degree',
|
||||
verified: true,
|
||||
ipfsHash: 'QmX7Y8Z9...',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: 'Blockchain Development Certificate',
|
||||
institution: 'Digital Kurdistan Academy',
|
||||
issueDate: '2023-03-20',
|
||||
certificateId: 'DKA-BC-2023-5678',
|
||||
type: 'course',
|
||||
verified: true,
|
||||
ipfsHash: 'QmA1B2C3...',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: 'Kurdish Language Proficiency',
|
||||
institution: 'Kurdistan Cultural Institute',
|
||||
issueDate: '2023-08-10',
|
||||
certificateId: 'KCI-KL-2023-9012',
|
||||
type: 'skill',
|
||||
verified: true,
|
||||
ipfsHash: 'QmD4E5F6...',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
title: 'Smart Contract Security',
|
||||
institution: 'PezkuwiChain Foundation',
|
||||
issueDate: '2024-01-15',
|
||||
certificateId: 'PKW-SCS-2024-3456',
|
||||
type: 'course',
|
||||
verified: false,
|
||||
},
|
||||
]);
|
||||
|
||||
const getCertificateIcon = (type: string) => {
|
||||
switch (type) {
|
||||
case 'degree':
|
||||
return 'school';
|
||||
case 'course':
|
||||
return 'book';
|
||||
case 'skill':
|
||||
return 'ribbon';
|
||||
case 'achievement':
|
||||
return 'trophy';
|
||||
default:
|
||||
return 'document';
|
||||
}
|
||||
};
|
||||
|
||||
const getCertificateColor = (type: string) => {
|
||||
switch (type) {
|
||||
case 'degree':
|
||||
return Colors.primary;
|
||||
case 'course':
|
||||
return Colors.success;
|
||||
case 'skill':
|
||||
return Colors.kurdishGold;
|
||||
case 'achievement':
|
||||
return Colors.coral;
|
||||
default:
|
||||
return Colors.textGray;
|
||||
}
|
||||
};
|
||||
|
||||
const shareCertificate = async (certificate: Certificate) => {
|
||||
try {
|
||||
await Share.share({
|
||||
message: `🎓 ${certificate.title}\n\nIssued by: ${certificate.institution}\nDate: ${certificate.issueDate}\nCertificate ID: ${certificate.certificateId}\n\nVerified on PezkuwiChain - Digital Kurdistan's Blockchain Platform`,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error sharing:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const verifyCertificate = (certificate: Certificate) => {
|
||||
if (certificate.verified) {
|
||||
Alert.alert(
|
||||
'✓ Verified Certificate',
|
||||
`This certificate is verified on PezkuwiChain blockchain.\n\nIPFS Hash: ${certificate.ipfsHash}\nCertificate ID: ${certificate.certificateId}`,
|
||||
[{ text: 'OK' }]
|
||||
);
|
||||
} else {
|
||||
Alert.alert(
|
||||
'Pending Verification',
|
||||
'This certificate is pending blockchain verification. Please check back later.',
|
||||
[{ text: 'OK' }]
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<ScrollView showsVerticalScrollIndicator={false}>
|
||||
{/* Header */}
|
||||
<LinearGradient
|
||||
colors={[Colors.primary, Colors.success]}
|
||||
style={styles.header}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
>
|
||||
<View style={styles.headerContent}>
|
||||
<View>
|
||||
<Text style={styles.headerTitle}>Perwerde</Text>
|
||||
<Text style={styles.headerSubtitle}>Education & Certificates</Text>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
style={styles.addButton}
|
||||
onPress={() =>
|
||||
Alert.alert(
|
||||
'Add Certificate',
|
||||
'Request your institution to issue a certificate on PezkuwiChain',
|
||||
[{ text: 'OK' }]
|
||||
)
|
||||
}
|
||||
>
|
||||
<Ionicons name="add" size={24} color="white" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
|
||||
{/* Statistics Grid */}
|
||||
<View style={styles.statsContainer}>
|
||||
<View style={styles.statsGrid}>
|
||||
<View style={styles.statCard}>
|
||||
<Ionicons
|
||||
name="document-text"
|
||||
size={28}
|
||||
color={Colors.primary}
|
||||
/>
|
||||
<Text style={styles.statValue}>{stats.totalCertificates}</Text>
|
||||
<Text style={styles.statLabel}>Certificates</Text>
|
||||
</View>
|
||||
<View style={styles.statCard}>
|
||||
<Ionicons
|
||||
name="checkmark-circle"
|
||||
size={28}
|
||||
color={Colors.success}
|
||||
/>
|
||||
<Text style={styles.statValue}>{stats.verifiedCertificates}</Text>
|
||||
<Text style={styles.statLabel}>Verified</Text>
|
||||
</View>
|
||||
<View style={styles.statCard}>
|
||||
<Ionicons name="bulb" size={28} color={Colors.kurdishGold} />
|
||||
<Text style={styles.statValue}>{stats.skillsAcquired}</Text>
|
||||
<Text style={styles.statLabel}>Skills</Text>
|
||||
</View>
|
||||
<View style={styles.statCard}>
|
||||
<Ionicons name="time" size={28} color={Colors.coral} />
|
||||
<Text style={styles.statValue}>{stats.learningHours}</Text>
|
||||
<Text style={styles.statLabel}>Hours</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Certificates Section */}
|
||||
<View style={styles.section}>
|
||||
<View style={styles.sectionHeader}>
|
||||
<Text style={styles.sectionTitle}>My Certificates</Text>
|
||||
<TouchableOpacity>
|
||||
<Text style={styles.viewAllText}>View All</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{certificates.map((certificate) => (
|
||||
<TouchableOpacity
|
||||
key={certificate.id}
|
||||
style={styles.certificateCard}
|
||||
onPress={() => verifyCertificate(certificate)}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<View style={styles.certificateHeader}>
|
||||
<View
|
||||
style={[
|
||||
styles.certificateIconContainer,
|
||||
{
|
||||
backgroundColor:
|
||||
getCertificateColor(certificate.type) + '20',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Ionicons
|
||||
name={getCertificateIcon(certificate.type)}
|
||||
size={28}
|
||||
color={getCertificateColor(certificate.type)}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.certificateInfo}>
|
||||
<Text style={styles.certificateTitle}>
|
||||
{certificate.title}
|
||||
</Text>
|
||||
<Text style={styles.certificateInstitution}>
|
||||
{certificate.institution}
|
||||
</Text>
|
||||
<Text style={styles.certificateDate}>
|
||||
Issued: {certificate.issueDate}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.certificateFooter}>
|
||||
<View style={styles.certificateId}>
|
||||
<Ionicons
|
||||
name="finger-print"
|
||||
size={14}
|
||||
color={Colors.textGray}
|
||||
/>
|
||||
<Text style={styles.certificateIdText}>
|
||||
{certificate.certificateId}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.certificateActions}>
|
||||
{certificate.verified && (
|
||||
<View style={styles.verifiedBadge}>
|
||||
<Ionicons
|
||||
name="shield-checkmark"
|
||||
size={14}
|
||||
color={Colors.success}
|
||||
/>
|
||||
<Text style={styles.verifiedText}>Verified</Text>
|
||||
</View>
|
||||
)}
|
||||
<TouchableOpacity
|
||||
onPress={() => shareCertificate(certificate)}
|
||||
style={styles.shareButton}
|
||||
>
|
||||
<Ionicons
|
||||
name="share-social-outline"
|
||||
size={20}
|
||||
color={Colors.primary}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
|
||||
{/* Learning Paths */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Recommended Learning Paths</Text>
|
||||
|
||||
<TouchableOpacity style={styles.pathCard} activeOpacity={0.7}>
|
||||
<LinearGradient
|
||||
colors={[Colors.primary + '20', Colors.success + '20']}
|
||||
style={styles.pathGradient}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
>
|
||||
<View style={styles.pathContent}>
|
||||
<View style={styles.pathIcon}>
|
||||
<Ionicons name="code-slash" size={32} color={Colors.primary} />
|
||||
</View>
|
||||
<View style={styles.pathInfo}>
|
||||
<Text style={styles.pathTitle}>
|
||||
Blockchain Developer Path
|
||||
</Text>
|
||||
<Text style={styles.pathDescription}>
|
||||
Master Substrate & Polkadot development
|
||||
</Text>
|
||||
<View style={styles.pathMeta}>
|
||||
<View style={styles.pathMetaItem}>
|
||||
<Ionicons name="book" size={14} color={Colors.textGray} />
|
||||
<Text style={styles.pathMetaText}>8 Courses</Text>
|
||||
</View>
|
||||
<View style={styles.pathMetaItem}>
|
||||
<Ionicons name="time" size={14} color={Colors.textGray} />
|
||||
<Text style={styles.pathMetaText}>120 Hours</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<Ionicons
|
||||
name="chevron-forward"
|
||||
size={24}
|
||||
color={Colors.textGray}
|
||||
/>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity style={styles.pathCard} activeOpacity={0.7}>
|
||||
<LinearGradient
|
||||
colors={[Colors.kurdishGold + '20', Colors.coral + '20']}
|
||||
style={styles.pathGradient}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
>
|
||||
<View style={styles.pathContent}>
|
||||
<View style={styles.pathIcon}>
|
||||
<Ionicons name="language" size={32} color={Colors.kurdishGold} />
|
||||
</View>
|
||||
<View style={styles.pathInfo}>
|
||||
<Text style={styles.pathTitle}>Kurdish Culture & Heritage</Text>
|
||||
<Text style={styles.pathDescription}>
|
||||
Learn Kurdish language and history
|
||||
</Text>
|
||||
<View style={styles.pathMeta}>
|
||||
<View style={styles.pathMetaItem}>
|
||||
<Ionicons name="book" size={14} color={Colors.textGray} />
|
||||
<Text style={styles.pathMetaText}>5 Courses</Text>
|
||||
</View>
|
||||
<View style={styles.pathMetaItem}>
|
||||
<Ionicons name="time" size={14} color={Colors.textGray} />
|
||||
<Text style={styles.pathMetaText}>60 Hours</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<Ionicons
|
||||
name="chevron-forward"
|
||||
size={24}
|
||||
color={Colors.textGray}
|
||||
/>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Info Section */}
|
||||
<View style={styles.infoSection}>
|
||||
<View style={styles.infoCard}>
|
||||
<Ionicons name="information-circle" size={24} color={Colors.primary} />
|
||||
<Text style={styles.infoText}>
|
||||
All certificates are stored on PezkuwiChain blockchain and IPFS,
|
||||
ensuring permanent verification and authenticity.
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={{ height: 40 }} />
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.background,
|
||||
},
|
||||
header: {
|
||||
paddingHorizontal: 20,
|
||||
paddingTop: 20,
|
||||
paddingBottom: 24,
|
||||
borderBottomLeftRadius: 24,
|
||||
borderBottomRightRadius: 24,
|
||||
},
|
||||
headerContent: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: 32,
|
||||
fontWeight: '700',
|
||||
color: 'white',
|
||||
marginBottom: 4,
|
||||
},
|
||||
headerSubtitle: {
|
||||
fontSize: 16,
|
||||
color: 'rgba(255, 255, 255, 0.9)',
|
||||
},
|
||||
addButton: {
|
||||
width: 48,
|
||||
height: 48,
|
||||
borderRadius: 24,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.2)',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
statsContainer: {
|
||||
paddingHorizontal: 20,
|
||||
marginTop: -30,
|
||||
marginBottom: 20,
|
||||
},
|
||||
statsGrid: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
gap: 12,
|
||||
},
|
||||
statCard: {
|
||||
flex: 1,
|
||||
minWidth: '47%',
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 14,
|
||||
padding: 16,
|
||||
alignItems: 'center',
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.05,
|
||||
shadowRadius: 8,
|
||||
elevation: 2,
|
||||
},
|
||||
statValue: {
|
||||
fontSize: 24,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
marginTop: 8,
|
||||
marginBottom: 4,
|
||||
},
|
||||
statLabel: {
|
||||
fontSize: 13,
|
||||
color: Colors.textGray,
|
||||
textAlign: 'center',
|
||||
},
|
||||
section: {
|
||||
paddingHorizontal: 20,
|
||||
marginBottom: 24,
|
||||
},
|
||||
sectionHeader: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 12,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 20,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
},
|
||||
viewAllText: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: Colors.primary,
|
||||
},
|
||||
certificateCard: {
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 14,
|
||||
padding: 16,
|
||||
marginBottom: 12,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.04,
|
||||
shadowRadius: 6,
|
||||
elevation: 1,
|
||||
},
|
||||
certificateHeader: {
|
||||
flexDirection: 'row',
|
||||
marginBottom: 12,
|
||||
},
|
||||
certificateIconContainer: {
|
||||
width: 56,
|
||||
height: 56,
|
||||
borderRadius: 12,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginRight: 12,
|
||||
},
|
||||
certificateInfo: {
|
||||
flex: 1,
|
||||
},
|
||||
certificateTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: Colors.textDark,
|
||||
marginBottom: 4,
|
||||
},
|
||||
certificateInstitution: {
|
||||
fontSize: 14,
|
||||
color: Colors.textGray,
|
||||
marginBottom: 2,
|
||||
},
|
||||
certificateDate: {
|
||||
fontSize: 12,
|
||||
color: Colors.textGray,
|
||||
},
|
||||
certificateFooter: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingTop: 12,
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: Colors.background,
|
||||
},
|
||||
certificateId: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
flex: 1,
|
||||
},
|
||||
certificateIdText: {
|
||||
fontSize: 12,
|
||||
color: Colors.textGray,
|
||||
fontFamily: 'monospace',
|
||||
},
|
||||
certificateActions: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 12,
|
||||
},
|
||||
verifiedBadge: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 4,
|
||||
backgroundColor: Colors.success + '20',
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 4,
|
||||
borderRadius: 8,
|
||||
},
|
||||
verifiedText: {
|
||||
fontSize: 12,
|
||||
fontWeight: '600',
|
||||
color: Colors.success,
|
||||
},
|
||||
shareButton: {
|
||||
padding: 4,
|
||||
},
|
||||
pathCard: {
|
||||
marginBottom: 12,
|
||||
borderRadius: 14,
|
||||
overflow: 'hidden',
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.04,
|
||||
shadowRadius: 6,
|
||||
elevation: 1,
|
||||
},
|
||||
pathGradient: {
|
||||
padding: 16,
|
||||
},
|
||||
pathContent: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
pathIcon: {
|
||||
width: 56,
|
||||
height: 56,
|
||||
borderRadius: 12,
|
||||
backgroundColor: 'white',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginRight: 12,
|
||||
},
|
||||
pathInfo: {
|
||||
flex: 1,
|
||||
},
|
||||
pathTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: Colors.textDark,
|
||||
marginBottom: 4,
|
||||
},
|
||||
pathDescription: {
|
||||
fontSize: 13,
|
||||
color: Colors.textGray,
|
||||
marginBottom: 8,
|
||||
},
|
||||
pathMeta: {
|
||||
flexDirection: 'row',
|
||||
gap: 16,
|
||||
},
|
||||
pathMetaItem: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 4,
|
||||
},
|
||||
pathMetaText: {
|
||||
fontSize: 12,
|
||||
color: Colors.textGray,
|
||||
},
|
||||
infoSection: {
|
||||
paddingHorizontal: 20,
|
||||
marginBottom: 24,
|
||||
},
|
||||
infoCard: {
|
||||
flexDirection: 'row',
|
||||
backgroundColor: Colors.primary + '10',
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
gap: 12,
|
||||
},
|
||||
infoText: {
|
||||
flex: 1,
|
||||
fontSize: 13,
|
||||
color: Colors.textDark,
|
||||
lineHeight: 20,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,792 +0,0 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
TextInput,
|
||||
Alert,
|
||||
} from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import Colors from '../../constants/colors';
|
||||
|
||||
interface ExchangeRate {
|
||||
hezToPez: number;
|
||||
pezToHez: number;
|
||||
lastUpdated: string;
|
||||
}
|
||||
|
||||
interface SwapHistory {
|
||||
id: string;
|
||||
fromToken: 'HEZ' | 'PEZ';
|
||||
toToken: 'HEZ' | 'PEZ';
|
||||
fromAmount: number;
|
||||
toAmount: number;
|
||||
rate: number;
|
||||
date: string;
|
||||
txHash: string;
|
||||
}
|
||||
|
||||
export default function ExchangeScreen({ navigation }: any) {
|
||||
const [fromToken, setFromToken] = useState<'HEZ' | 'PEZ'>('HEZ');
|
||||
const [toToken, setToToken] = useState<'HEZ' | 'PEZ'>('PEZ');
|
||||
const [fromAmount, setFromAmount] = useState('');
|
||||
const [toAmount, setToAmount] = useState('');
|
||||
const [slippage, setSlippage] = useState('0.5');
|
||||
|
||||
const [balances] = useState({
|
||||
hez: 45750.5,
|
||||
pez: 1234567,
|
||||
});
|
||||
|
||||
const [exchangeRate] = useState<ExchangeRate>({
|
||||
hezToPez: 27.5,
|
||||
pezToHez: 0.0364,
|
||||
lastUpdated: new Date().toLocaleTimeString(),
|
||||
});
|
||||
|
||||
const [swapHistory] = useState<SwapHistory[]>([
|
||||
{
|
||||
id: '1',
|
||||
fromToken: 'HEZ',
|
||||
toToken: 'PEZ',
|
||||
fromAmount: 100,
|
||||
toAmount: 2750,
|
||||
rate: 27.5,
|
||||
date: '2024-01-23 14:30',
|
||||
txHash: '0x1a2b3c...',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
fromToken: 'PEZ',
|
||||
toToken: 'HEZ',
|
||||
fromAmount: 5000,
|
||||
toAmount: 182,
|
||||
rate: 0.0364,
|
||||
date: '2024-01-22 10:15',
|
||||
txHash: '0x4d5e6f...',
|
||||
},
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
calculateToAmount();
|
||||
}, [fromAmount, fromToken, toToken]);
|
||||
|
||||
const calculateToAmount = () => {
|
||||
if (!fromAmount || parseFloat(fromAmount) <= 0) {
|
||||
setToAmount('');
|
||||
return;
|
||||
}
|
||||
|
||||
const amount = parseFloat(fromAmount);
|
||||
let result = 0;
|
||||
|
||||
if (fromToken === 'HEZ' && toToken === 'PEZ') {
|
||||
result = amount * exchangeRate.hezToPez;
|
||||
} else if (fromToken === 'PEZ' && toToken === 'HEZ') {
|
||||
result = amount * exchangeRate.pezToHez;
|
||||
}
|
||||
|
||||
// Apply slippage
|
||||
const slippagePercent = parseFloat(slippage) / 100;
|
||||
result = result * (1 - slippagePercent);
|
||||
|
||||
setToAmount(result.toFixed(4));
|
||||
};
|
||||
|
||||
const swapTokens = () => {
|
||||
const newFromToken = toToken;
|
||||
const newToToken = fromToken;
|
||||
setFromToken(newFromToken);
|
||||
setToToken(newToToken);
|
||||
setFromAmount(toAmount);
|
||||
};
|
||||
|
||||
const executeSwap = () => {
|
||||
if (!fromAmount || parseFloat(fromAmount) <= 0) {
|
||||
Alert.alert('Invalid Amount', 'Please enter a valid amount to swap');
|
||||
return;
|
||||
}
|
||||
|
||||
const amount = parseFloat(fromAmount);
|
||||
const currentBalance = fromToken === 'HEZ' ? balances.hez : balances.pez;
|
||||
|
||||
if (amount > currentBalance) {
|
||||
Alert.alert('Insufficient Balance', `You don't have enough ${fromToken}`);
|
||||
return;
|
||||
}
|
||||
|
||||
Alert.alert(
|
||||
'Confirm Swap',
|
||||
`Swap ${fromAmount} ${fromToken} for ${toAmount} ${toToken}?\n\nRate: 1 ${fromToken} = ${
|
||||
fromToken === 'HEZ' ? exchangeRate.hezToPez : exchangeRate.pezToHez
|
||||
} ${toToken}\nSlippage: ${slippage}%`,
|
||||
[
|
||||
{ text: 'Cancel', style: 'cancel' },
|
||||
{
|
||||
text: 'Confirm',
|
||||
onPress: () => {
|
||||
Alert.alert(
|
||||
'Success!',
|
||||
`Swap executed successfully!\n\nTransaction hash: 0x${Math.random()
|
||||
.toString(16)
|
||||
.substr(2, 8)}...`
|
||||
);
|
||||
setFromAmount('');
|
||||
setToAmount('');
|
||||
},
|
||||
},
|
||||
]
|
||||
);
|
||||
};
|
||||
|
||||
const setMaxAmount = () => {
|
||||
const maxBalance = fromToken === 'HEZ' ? balances.hez : balances.pez;
|
||||
setFromAmount(maxBalance.toString());
|
||||
};
|
||||
|
||||
const getCurrentRate = () => {
|
||||
return fromToken === 'HEZ' ? exchangeRate.hezToPez : exchangeRate.pezToHez;
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<ScrollView showsVerticalScrollIndicator={false}>
|
||||
{/* Header */}
|
||||
<LinearGradient
|
||||
colors={[Colors.primary, Colors.kurdishGold]}
|
||||
style={styles.header}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
>
|
||||
<View style={styles.headerContent}>
|
||||
<View>
|
||||
<Text style={styles.headerTitle}>Exchange</Text>
|
||||
<Text style={styles.headerSubtitle}>Swap HEZ ↔ PEZ Tokens</Text>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
style={styles.historyButton}
|
||||
onPress={() => Alert.alert('History', 'Full swap history coming soon')}
|
||||
>
|
||||
<Ionicons name="time-outline" size={24} color="white" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
|
||||
{/* Exchange Rate Card */}
|
||||
<View style={styles.rateContainer}>
|
||||
<View style={styles.rateCard}>
|
||||
<View style={styles.rateHeader}>
|
||||
<Text style={styles.rateTitle}>Current Exchange Rate</Text>
|
||||
<View style={styles.updateBadge}>
|
||||
<Ionicons name="sync" size={12} color={Colors.success} />
|
||||
<Text style={styles.updateText}>Live</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.rateContent}>
|
||||
<View style={styles.rateItem}>
|
||||
<Text style={styles.rateLabel}>1 HEZ =</Text>
|
||||
<Text style={styles.rateValue}>{exchangeRate.hezToPez} PEZ</Text>
|
||||
</View>
|
||||
<View style={styles.rateDivider} />
|
||||
<View style={styles.rateItem}>
|
||||
<Text style={styles.rateLabel}>1 PEZ =</Text>
|
||||
<Text style={styles.rateValue}>{exchangeRate.pezToHez} HEZ</Text>
|
||||
</View>
|
||||
</View>
|
||||
<Text style={styles.rateUpdate}>
|
||||
Last updated: {exchangeRate.lastUpdated}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Swap Interface */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Swap Tokens</Text>
|
||||
|
||||
{/* From Token */}
|
||||
<View style={styles.swapCard}>
|
||||
<View style={styles.swapHeader}>
|
||||
<Text style={styles.swapLabel}>From</Text>
|
||||
<Text style={styles.balanceText}>
|
||||
Balance: {fromToken === 'HEZ' ? balances.hez.toLocaleString() : balances.pez.toLocaleString()} {fromToken}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.inputContainer}>
|
||||
<TextInput
|
||||
style={styles.amountInput}
|
||||
placeholder="0.00"
|
||||
keyboardType="decimal-pad"
|
||||
value={fromAmount}
|
||||
onChangeText={setFromAmount}
|
||||
/>
|
||||
<View style={styles.tokenSelector}>
|
||||
<View style={styles.tokenBadge}>
|
||||
<Text style={styles.tokenText}>{fromToken}</Text>
|
||||
</View>
|
||||
<TouchableOpacity onPress={setMaxAmount} style={styles.maxButton}>
|
||||
<Text style={styles.maxButtonText}>MAX</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Swap Button */}
|
||||
<View style={styles.swapButtonContainer}>
|
||||
<TouchableOpacity
|
||||
style={styles.swapIconButton}
|
||||
onPress={swapTokens}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Ionicons name="swap-vertical" size={24} color={Colors.primary} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* To Token */}
|
||||
<View style={styles.swapCard}>
|
||||
<View style={styles.swapHeader}>
|
||||
<Text style={styles.swapLabel}>To</Text>
|
||||
<Text style={styles.balanceText}>
|
||||
Balance: {toToken === 'HEZ' ? balances.hez.toLocaleString() : balances.pez.toLocaleString()} {toToken}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.inputContainer}>
|
||||
<TextInput
|
||||
style={[styles.amountInput, styles.amountInputDisabled]}
|
||||
placeholder="0.00"
|
||||
value={toAmount}
|
||||
editable={false}
|
||||
/>
|
||||
<View style={styles.tokenSelector}>
|
||||
<View style={styles.tokenBadge}>
|
||||
<Text style={styles.tokenText}>{toToken}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Swap Details */}
|
||||
{fromAmount && toAmount && (
|
||||
<View style={styles.detailsCard}>
|
||||
<View style={styles.detailRow}>
|
||||
<Text style={styles.detailLabel}>Rate</Text>
|
||||
<Text style={styles.detailValue}>
|
||||
1 {fromToken} = {getCurrentRate()} {toToken}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.detailRow}>
|
||||
<Text style={styles.detailLabel}>Slippage Tolerance</Text>
|
||||
<View style={styles.slippageSelector}>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.slippageOption,
|
||||
slippage === '0.5' && styles.slippageOptionActive,
|
||||
]}
|
||||
onPress={() => setSlippage('0.5')}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
styles.slippageText,
|
||||
slippage === '0.5' && styles.slippageTextActive,
|
||||
]}
|
||||
>
|
||||
0.5%
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.slippageOption,
|
||||
slippage === '1.0' && styles.slippageOptionActive,
|
||||
]}
|
||||
onPress={() => setSlippage('1.0')}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
styles.slippageText,
|
||||
slippage === '1.0' && styles.slippageTextActive,
|
||||
]}
|
||||
>
|
||||
1.0%
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.slippageOption,
|
||||
slippage === '2.0' && styles.slippageOptionActive,
|
||||
]}
|
||||
onPress={() => setSlippage('2.0')}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
styles.slippageText,
|
||||
slippage === '2.0' && styles.slippageTextActive,
|
||||
]}
|
||||
>
|
||||
2.0%
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.detailRow}>
|
||||
<Text style={styles.detailLabel}>Network Fee</Text>
|
||||
<Text style={styles.detailValue}>~0.01 HEZ</Text>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* Execute Swap Button */}
|
||||
<TouchableOpacity
|
||||
style={styles.executeButton}
|
||||
onPress={executeSwap}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={[Colors.primary, Colors.success]}
|
||||
style={styles.executeButtonGradient}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 0 }}
|
||||
>
|
||||
<Ionicons name="swap-horizontal" size={20} color="white" />
|
||||
<Text style={styles.executeButtonText}>Swap Tokens</Text>
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Recent Swaps */}
|
||||
<View style={styles.section}>
|
||||
<View style={styles.sectionHeader}>
|
||||
<Text style={styles.sectionTitle}>Recent Swaps</Text>
|
||||
<TouchableOpacity>
|
||||
<Text style={styles.viewAllText}>View All</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{swapHistory.map((swap) => (
|
||||
<View key={swap.id} style={styles.historyCard}>
|
||||
<View style={styles.historyHeader}>
|
||||
<View style={styles.historyIcon}>
|
||||
<Ionicons
|
||||
name="swap-horizontal"
|
||||
size={24}
|
||||
color={Colors.primary}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.historyInfo}>
|
||||
<Text style={styles.historyTitle}>
|
||||
{swap.fromToken} → {swap.toToken}
|
||||
</Text>
|
||||
<Text style={styles.historyDate}>{swap.date}</Text>
|
||||
<Text style={styles.historyHash}>Tx: {swap.txHash}</Text>
|
||||
</View>
|
||||
<View style={styles.historyAmount}>
|
||||
<Text style={styles.historyFromAmount}>
|
||||
-{swap.fromAmount} {swap.fromToken}
|
||||
</Text>
|
||||
<Text style={styles.historyToAmount}>
|
||||
+{swap.toAmount} {swap.toToken}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.historyFooter}>
|
||||
<Text style={styles.historyRate}>
|
||||
Rate: 1 {swap.fromToken} = {swap.rate} {swap.toToken}
|
||||
</Text>
|
||||
<TouchableOpacity>
|
||||
<Ionicons
|
||||
name="open-outline"
|
||||
size={16}
|
||||
color={Colors.primary}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
|
||||
{/* Info Section */}
|
||||
<View style={styles.infoSection}>
|
||||
<View style={styles.infoCard}>
|
||||
<Ionicons name="information-circle" size={24} color={Colors.primary} />
|
||||
<View style={styles.infoContent}>
|
||||
<Text style={styles.infoTitle}>About Token Swap</Text>
|
||||
<Text style={styles.infoText}>
|
||||
Exchange rates are determined by the on-chain liquidity pool. HEZ is the security layer token, while PEZ is the governance token. Swap fees support network validators and liquidity providers.
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={{ height: 40 }} />
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.background,
|
||||
},
|
||||
header: {
|
||||
paddingHorizontal: 20,
|
||||
paddingTop: 20,
|
||||
paddingBottom: 24,
|
||||
borderBottomLeftRadius: 24,
|
||||
borderBottomRightRadius: 24,
|
||||
},
|
||||
headerContent: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: 32,
|
||||
fontWeight: '700',
|
||||
color: 'white',
|
||||
marginBottom: 4,
|
||||
},
|
||||
headerSubtitle: {
|
||||
fontSize: 16,
|
||||
color: 'rgba(255, 255, 255, 0.9)',
|
||||
},
|
||||
historyButton: {
|
||||
width: 48,
|
||||
height: 48,
|
||||
borderRadius: 24,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.2)',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
rateContainer: {
|
||||
paddingHorizontal: 20,
|
||||
marginTop: -30,
|
||||
marginBottom: 20,
|
||||
},
|
||||
rateCard: {
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 16,
|
||||
padding: 20,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.05,
|
||||
shadowRadius: 8,
|
||||
elevation: 2,
|
||||
},
|
||||
rateHeader: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 16,
|
||||
},
|
||||
rateTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: Colors.textDark,
|
||||
},
|
||||
updateBadge: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 4,
|
||||
backgroundColor: Colors.success + '20',
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 4,
|
||||
borderRadius: 8,
|
||||
},
|
||||
updateText: {
|
||||
fontSize: 12,
|
||||
fontWeight: '600',
|
||||
color: Colors.success,
|
||||
},
|
||||
rateContent: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginBottom: 12,
|
||||
},
|
||||
rateItem: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
},
|
||||
rateLabel: {
|
||||
fontSize: 14,
|
||||
color: Colors.textGray,
|
||||
marginBottom: 4,
|
||||
},
|
||||
rateValue: {
|
||||
fontSize: 18,
|
||||
fontWeight: '700',
|
||||
color: Colors.primary,
|
||||
},
|
||||
rateDivider: {
|
||||
width: 1,
|
||||
height: 40,
|
||||
backgroundColor: Colors.background,
|
||||
},
|
||||
rateUpdate: {
|
||||
fontSize: 12,
|
||||
color: Colors.textGray,
|
||||
textAlign: 'center',
|
||||
},
|
||||
section: {
|
||||
paddingHorizontal: 20,
|
||||
marginBottom: 24,
|
||||
},
|
||||
sectionHeader: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 12,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 20,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
marginBottom: 12,
|
||||
},
|
||||
viewAllText: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: Colors.primary,
|
||||
},
|
||||
swapCard: {
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 14,
|
||||
padding: 16,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.04,
|
||||
shadowRadius: 6,
|
||||
elevation: 1,
|
||||
},
|
||||
swapHeader: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 12,
|
||||
},
|
||||
swapLabel: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: Colors.textGray,
|
||||
},
|
||||
balanceText: {
|
||||
fontSize: 12,
|
||||
color: Colors.textGray,
|
||||
},
|
||||
inputContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 12,
|
||||
},
|
||||
amountInput: {
|
||||
flex: 1,
|
||||
fontSize: 24,
|
||||
fontWeight: '600',
|
||||
color: Colors.textDark,
|
||||
},
|
||||
amountInputDisabled: {
|
||||
color: Colors.textGray,
|
||||
},
|
||||
tokenSelector: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
},
|
||||
tokenBadge: {
|
||||
backgroundColor: Colors.primary + '20',
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 8,
|
||||
borderRadius: 10,
|
||||
},
|
||||
tokenText: {
|
||||
fontSize: 16,
|
||||
fontWeight: '700',
|
||||
color: Colors.primary,
|
||||
},
|
||||
maxButton: {
|
||||
backgroundColor: Colors.background,
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 6,
|
||||
borderRadius: 8,
|
||||
},
|
||||
maxButtonText: {
|
||||
fontSize: 12,
|
||||
fontWeight: '700',
|
||||
color: Colors.primary,
|
||||
},
|
||||
swapButtonContainer: {
|
||||
alignItems: 'center',
|
||||
marginVertical: -12,
|
||||
zIndex: 10,
|
||||
},
|
||||
swapIconButton: {
|
||||
width: 48,
|
||||
height: 48,
|
||||
borderRadius: 24,
|
||||
backgroundColor: 'white',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 8,
|
||||
elevation: 3,
|
||||
},
|
||||
detailsCard: {
|
||||
backgroundColor: Colors.background,
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
marginTop: 16,
|
||||
gap: 12,
|
||||
},
|
||||
detailRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
},
|
||||
detailLabel: {
|
||||
fontSize: 14,
|
||||
color: Colors.textGray,
|
||||
},
|
||||
detailValue: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: Colors.textDark,
|
||||
},
|
||||
slippageSelector: {
|
||||
flexDirection: 'row',
|
||||
gap: 8,
|
||||
},
|
||||
slippageOption: {
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 6,
|
||||
borderRadius: 8,
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
slippageOptionActive: {
|
||||
backgroundColor: Colors.primary,
|
||||
},
|
||||
slippageText: {
|
||||
fontSize: 12,
|
||||
fontWeight: '600',
|
||||
color: Colors.textGray,
|
||||
},
|
||||
slippageTextActive: {
|
||||
color: 'white',
|
||||
},
|
||||
executeButton: {
|
||||
borderRadius: 12,
|
||||
overflow: 'hidden',
|
||||
marginTop: 20,
|
||||
},
|
||||
executeButtonGradient: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingVertical: 16,
|
||||
gap: 8,
|
||||
},
|
||||
executeButtonText: {
|
||||
fontSize: 16,
|
||||
fontWeight: '700',
|
||||
color: 'white',
|
||||
},
|
||||
historyCard: {
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 14,
|
||||
padding: 16,
|
||||
marginBottom: 12,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.04,
|
||||
shadowRadius: 6,
|
||||
elevation: 1,
|
||||
},
|
||||
historyHeader: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginBottom: 12,
|
||||
},
|
||||
historyIcon: {
|
||||
width: 44,
|
||||
height: 44,
|
||||
borderRadius: 22,
|
||||
backgroundColor: Colors.primary + '20',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginRight: 12,
|
||||
},
|
||||
historyInfo: {
|
||||
flex: 1,
|
||||
},
|
||||
historyTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: Colors.textDark,
|
||||
marginBottom: 2,
|
||||
},
|
||||
historyDate: {
|
||||
fontSize: 12,
|
||||
color: Colors.textGray,
|
||||
marginBottom: 2,
|
||||
},
|
||||
historyHash: {
|
||||
fontSize: 11,
|
||||
color: Colors.textGray,
|
||||
fontFamily: 'monospace',
|
||||
},
|
||||
historyAmount: {
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
historyFromAmount: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: Colors.error,
|
||||
marginBottom: 2,
|
||||
},
|
||||
historyToAmount: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: Colors.success,
|
||||
},
|
||||
historyFooter: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingTop: 12,
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: Colors.background,
|
||||
},
|
||||
historyRate: {
|
||||
fontSize: 12,
|
||||
color: Colors.textGray,
|
||||
},
|
||||
infoSection: {
|
||||
paddingHorizontal: 20,
|
||||
marginBottom: 24,
|
||||
},
|
||||
infoCard: {
|
||||
flexDirection: 'row',
|
||||
backgroundColor: Colors.primary + '10',
|
||||
borderRadius: 14,
|
||||
padding: 16,
|
||||
gap: 12,
|
||||
},
|
||||
infoContent: {
|
||||
flex: 1,
|
||||
},
|
||||
infoTitle: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: Colors.textDark,
|
||||
marginBottom: 4,
|
||||
},
|
||||
infoText: {
|
||||
fontSize: 13,
|
||||
color: Colors.textDark,
|
||||
lineHeight: 20,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,416 +0,0 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
Alert,
|
||||
} from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import Colors from '../../constants/colors';
|
||||
import { Typography, Spacing, BorderRadius, Shadow } from '../../constants/theme';
|
||||
|
||||
interface GovernanceService {
|
||||
id: string;
|
||||
name: string;
|
||||
nameKu: string;
|
||||
icon: keyof typeof Ionicons.glyphMap;
|
||||
color: string;
|
||||
description: string;
|
||||
route?: string;
|
||||
}
|
||||
|
||||
export default function GovernanceScreen({ navigation }: any) {
|
||||
const [isHemwelati, setIsHemwelati] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
checkKYCStatus();
|
||||
}, []);
|
||||
|
||||
const checkKYCStatus = async () => {
|
||||
try {
|
||||
const kycData = await AsyncStorage.getItem('kyc_data');
|
||||
const kycStatus = await AsyncStorage.getItem('kyc_status');
|
||||
|
||||
if (kycData && kycStatus === 'approved') {
|
||||
setIsHemwelati(true);
|
||||
} else {
|
||||
setIsHemwelati(false);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error checking KYC status:', error);
|
||||
setIsHemwelati(false);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Main governance services (not ministries)
|
||||
const services: GovernanceService[] = [
|
||||
{
|
||||
id: 'presidency',
|
||||
name: 'Presidency',
|
||||
nameKu: 'Serokayetî',
|
||||
icon: 'business',
|
||||
color: '#E74C3C',
|
||||
description: 'Office of the President',
|
||||
},
|
||||
{
|
||||
id: 'parliament',
|
||||
name: 'Parliament',
|
||||
nameKu: 'Meclîs',
|
||||
icon: 'people',
|
||||
color: '#3498DB',
|
||||
description: 'Legislative Assembly - 201 MPs',
|
||||
},
|
||||
{
|
||||
id: 'ministries',
|
||||
name: 'Ministries',
|
||||
nameKu: 'Wezaretî',
|
||||
icon: 'briefcase',
|
||||
color: '#9B59B6',
|
||||
description: 'All Cabinet Ministries',
|
||||
route: 'Ministries',
|
||||
},
|
||||
{
|
||||
id: 'voting',
|
||||
name: 'Voting',
|
||||
nameKu: 'Dengdan',
|
||||
icon: 'checkmark-circle',
|
||||
color: '#1ABC9C',
|
||||
description: 'Proposals & Democratic Voting',
|
||||
},
|
||||
{
|
||||
id: 'p2p',
|
||||
name: 'P2P Services',
|
||||
nameKu: 'Karûbarên P2P',
|
||||
icon: 'people-circle',
|
||||
color: '#26A69A',
|
||||
description: 'Peer-to-Peer Transactions',
|
||||
},
|
||||
{
|
||||
id: 'b2b',
|
||||
name: 'B2B Services',
|
||||
nameKu: 'Karûbarên B2B',
|
||||
icon: 'business-outline',
|
||||
color: '#FF9800',
|
||||
description: 'Business-to-Business Platform',
|
||||
},
|
||||
{
|
||||
id: 'digital',
|
||||
name: 'Digital Infrastructure',
|
||||
nameKu: 'Binyata Dîjîtal',
|
||||
icon: 'server',
|
||||
color: '#26C6DA',
|
||||
description: 'Technology & Innovation Hub',
|
||||
},
|
||||
{
|
||||
id: 'citizenship',
|
||||
name: 'Citizenship Affairs',
|
||||
nameKu: 'Karûbarên Hemwelatî',
|
||||
icon: 'card',
|
||||
color: '#66BB6A',
|
||||
description: 'Identity & Registration Services',
|
||||
},
|
||||
{
|
||||
id: 'treasury',
|
||||
name: 'Public Treasury',
|
||||
nameKu: 'Xizêneya Giştî',
|
||||
icon: 'wallet',
|
||||
color: '#F39C12',
|
||||
description: 'National Budget & Spending',
|
||||
},
|
||||
{
|
||||
id: 'judiciary',
|
||||
name: 'Judiciary',
|
||||
nameKu: 'Dadwerî',
|
||||
icon: 'scale',
|
||||
color: '#34495E',
|
||||
description: 'Court System & Justice',
|
||||
},
|
||||
{
|
||||
id: 'elections',
|
||||
name: 'Elections',
|
||||
nameKu: 'Hilbijartinî',
|
||||
icon: 'ballot',
|
||||
color: '#5C6BC0',
|
||||
description: 'Electoral Commission',
|
||||
},
|
||||
{
|
||||
id: 'ombudsman',
|
||||
name: 'Ombudsman',
|
||||
nameKu: 'Parêzerê Mafan',
|
||||
icon: 'shield-checkmark',
|
||||
color: '#EC407A',
|
||||
description: 'Citizens Rights Protection',
|
||||
},
|
||||
];
|
||||
|
||||
const handleServicePress = (service: GovernanceService) => {
|
||||
if (!isHemwelati) {
|
||||
Alert.alert(
|
||||
'Access Restricted',
|
||||
'You must complete Identity KYC verification to access Governance features.',
|
||||
[
|
||||
{ text: 'Cancel', style: 'cancel' },
|
||||
{
|
||||
text: 'Complete KYC',
|
||||
onPress: () => navigation.navigate('Identity'),
|
||||
},
|
||||
]
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Navigate to specific route if available
|
||||
if (service.route) {
|
||||
navigation.navigate(service.route);
|
||||
return;
|
||||
}
|
||||
|
||||
// Show placeholder for other services
|
||||
Alert.alert(
|
||||
service.name,
|
||||
`${service.nameKu}\n\n${service.description}\n\nThis feature is under development.`,
|
||||
[{ text: 'OK' }]
|
||||
);
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<View style={styles.loadingContainer}>
|
||||
<Text style={styles.loadingText}>Loading...</Text>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
if (!isHemwelati) {
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<View style={styles.restrictedContainer}>
|
||||
<Ionicons name="lock-closed" size={80} color={Colors.textLight} />
|
||||
<Text style={styles.restrictedTitle}>Access Restricted</Text>
|
||||
<Text style={styles.restrictedText}>
|
||||
Governance features are only available to verified Hemwelatî (Digital Citizens).
|
||||
</Text>
|
||||
<Text style={styles.restrictedText}>
|
||||
Complete your Identity KYC verification to access:
|
||||
</Text>
|
||||
<View style={styles.featureList}>
|
||||
<Text style={styles.featureItem}>• Vote on proposals</Text>
|
||||
<Text style={styles.featureItem}>• Participate in governance</Text>
|
||||
<Text style={styles.featureItem}>• Access government services</Text>
|
||||
<Text style={styles.featureItem}>• View parliamentary sessions</Text>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
style={styles.kycButton}
|
||||
onPress={() => navigation.navigate('Identity')}
|
||||
>
|
||||
<Ionicons name="checkmark-circle" size={20} color="#FFFFFF" />
|
||||
<Text style={styles.kycButtonText}>Complete Identity KYC</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
{/* Header */}
|
||||
<View style={styles.header}>
|
||||
<View style={styles.headerContent}>
|
||||
<Text style={styles.headerTitle}>Welati Governance</Text>
|
||||
<Text style={styles.headerSubtitle}>Komara Kurdistanê</Text>
|
||||
</View>
|
||||
<View style={styles.verifiedBadge}>
|
||||
<Ionicons name="checkmark-circle" size={20} color="#27AE60" />
|
||||
<Text style={styles.verifiedText}>Verified Citizen</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<ScrollView style={styles.content} showsVerticalScrollIndicator={false}>
|
||||
{/* Services Grid */}
|
||||
<View style={styles.grid}>
|
||||
{services.map((service) => (
|
||||
<TouchableOpacity
|
||||
key={service.id}
|
||||
style={styles.serviceCard}
|
||||
onPress={() => handleServicePress(service)}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<View style={[styles.iconContainer, { backgroundColor: service.color }]}>
|
||||
<Ionicons name={service.icon} size={32} color="#FFFFFF" />
|
||||
</View>
|
||||
<Text style={styles.serviceName}>{service.name}</Text>
|
||||
<Text style={styles.serviceNameKu}>{service.nameKu}</Text>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
|
||||
{/* Info Footer */}
|
||||
<View style={styles.infoFooter}>
|
||||
<Ionicons name="information-circle" size={20} color={Colors.primary} />
|
||||
<Text style={styles.infoText}>
|
||||
As a verified Hemwelatî, you have full access to all governance features.
|
||||
</Text>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.background,
|
||||
},
|
||||
loadingContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
loadingText: {
|
||||
fontSize: Typography.sizes.lg,
|
||||
color: Colors.textLight,
|
||||
},
|
||||
restrictedContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: Spacing.xl,
|
||||
},
|
||||
restrictedTitle: {
|
||||
fontSize: Typography.sizes.xxl,
|
||||
fontWeight: Typography.weights.bold,
|
||||
color: Colors.textDark,
|
||||
marginTop: Spacing.lg,
|
||||
marginBottom: Spacing.md,
|
||||
},
|
||||
restrictedText: {
|
||||
fontSize: Typography.sizes.md,
|
||||
color: Colors.textLight,
|
||||
textAlign: 'center',
|
||||
marginBottom: Spacing.md,
|
||||
lineHeight: 22,
|
||||
},
|
||||
featureList: {
|
||||
marginTop: Spacing.md,
|
||||
marginBottom: Spacing.xl,
|
||||
},
|
||||
featureItem: {
|
||||
fontSize: Typography.sizes.md,
|
||||
color: Colors.textDark,
|
||||
marginBottom: Spacing.xs,
|
||||
},
|
||||
kycButton: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: Colors.primary,
|
||||
paddingHorizontal: Spacing.xl,
|
||||
paddingVertical: Spacing.md,
|
||||
borderRadius: BorderRadius.lg,
|
||||
...Shadow.medium,
|
||||
},
|
||||
kycButtonText: {
|
||||
fontSize: Typography.sizes.lg,
|
||||
fontWeight: Typography.weights.bold,
|
||||
color: '#FFFFFF',
|
||||
marginLeft: Spacing.sm,
|
||||
},
|
||||
header: {
|
||||
backgroundColor: '#FFFFFF',
|
||||
paddingHorizontal: Spacing.lg,
|
||||
paddingVertical: Spacing.md,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#E0E0E0',
|
||||
...Shadow.small,
|
||||
},
|
||||
headerContent: {
|
||||
marginBottom: Spacing.sm,
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: Typography.sizes.xxl,
|
||||
fontWeight: Typography.weights.bold,
|
||||
color: Colors.textDark,
|
||||
},
|
||||
headerSubtitle: {
|
||||
fontSize: Typography.sizes.md,
|
||||
color: Colors.textLight,
|
||||
marginTop: Spacing.xs,
|
||||
},
|
||||
verifiedBadge: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#E8F5E9',
|
||||
paddingHorizontal: Spacing.md,
|
||||
paddingVertical: Spacing.xs,
|
||||
borderRadius: BorderRadius.md,
|
||||
alignSelf: 'flex-start',
|
||||
},
|
||||
verifiedText: {
|
||||
fontSize: Typography.sizes.sm,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: '#27AE60',
|
||||
marginLeft: Spacing.xs,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
},
|
||||
grid: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
padding: Spacing.md,
|
||||
},
|
||||
serviceCard: {
|
||||
width: '31%',
|
||||
marginHorizontal: '1%',
|
||||
marginBottom: Spacing.lg,
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: BorderRadius.lg,
|
||||
padding: Spacing.md,
|
||||
alignItems: 'center',
|
||||
...Shadow.small,
|
||||
},
|
||||
iconContainer: {
|
||||
width: 64,
|
||||
height: 64,
|
||||
borderRadius: BorderRadius.lg,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginBottom: Spacing.sm,
|
||||
},
|
||||
serviceName: {
|
||||
fontSize: Typography.sizes.xs,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.textDark,
|
||||
textAlign: 'center',
|
||||
marginBottom: Spacing.xs,
|
||||
},
|
||||
serviceNameKu: {
|
||||
fontSize: Typography.sizes.xs,
|
||||
color: Colors.textLight,
|
||||
textAlign: 'center',
|
||||
},
|
||||
infoFooter: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#E3F2FD',
|
||||
margin: Spacing.lg,
|
||||
padding: Spacing.md,
|
||||
borderRadius: BorderRadius.md,
|
||||
},
|
||||
infoText: {
|
||||
flex: 1,
|
||||
fontSize: Typography.sizes.sm,
|
||||
color: Colors.primary,
|
||||
marginLeft: Spacing.sm,
|
||||
lineHeight: 18,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { View, Text, StyleSheet, TouchableOpacity, SafeAreaView, ActivityIndicator } from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import Colors from '../../constants/colors';
|
||||
import { Typography, Spacing, BorderRadius, Shadow } from '../../constants/theme';
|
||||
import { kycService } from '../../services/kycService';
|
||||
|
||||
export default function GovernanceScreen({ navigation }: any) {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [hasAccess, setHasAccess] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
checkAccess();
|
||||
}, []);
|
||||
|
||||
const checkAccess = async () => {
|
||||
try {
|
||||
const access = await kycService.hasGovernanceAccess();
|
||||
setHasAccess(access);
|
||||
} catch (error) {
|
||||
console.error('Failed to check governance access:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<ActivityIndicator size="large" color={Colors.mint} />
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
// If user doesn't have access (KYC not approved)
|
||||
if (!hasAccess) {
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.title}>Governance (Welati)</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.content}>
|
||||
<View style={styles.lockedCard}>
|
||||
<Ionicons name="lock-closed" size={60} color={Colors.textGray} />
|
||||
<Text style={styles.lockedTitle}>Access Restricted</Text>
|
||||
<Text style={styles.lockedSubtitle}>
|
||||
You need to complete Identity KYC verification to access Governance features.
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.requirementsCard}>
|
||||
<Text style={styles.requirementsTitle}>Requirements:</Text>
|
||||
<View style={styles.requirementItem}>
|
||||
<Ionicons name="person-outline" size={20} color={Colors.teal} />
|
||||
<Text style={styles.requirementText}>Complete Identity KYC form</Text>
|
||||
</View>
|
||||
<View style={styles.requirementItem}>
|
||||
<Ionicons name="checkmark-circle-outline" size={20} color={Colors.teal} />
|
||||
<Text style={styles.requirementText}>Get KYC approval on blockchain</Text>
|
||||
</View>
|
||||
<View style={styles.requirementItem}>
|
||||
<Ionicons name="card-outline" size={20} color={Colors.teal} />
|
||||
<Text style={styles.requirementText}>Receive Kurdistan Digital Citizen card</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.completeButton}
|
||||
onPress={() => navigation.navigate('Identity')}
|
||||
>
|
||||
<Text style={styles.completeButtonText}>Complete Identity KYC</Text>
|
||||
<Ionicons name="arrow-forward" size={20} color="#FFFFFF" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
// If user has access, show governance features
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.title}>Governance (Welati)</Text>
|
||||
<View style={styles.citizenBadge}>
|
||||
<Ionicons name="shield-checkmark" size={16} color={Colors.mint} />
|
||||
<Text style={styles.citizenBadgeText}>Verified Citizen</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.content}>
|
||||
<Text style={styles.sectionTitle}>Active Proposals</Text>
|
||||
<Text style={styles.comingSoon}>Coming soon...</Text>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: { flex: 1, backgroundColor: Colors.background },
|
||||
header: { padding: Spacing.xl, borderBottomWidth: 1, borderBottomColor: '#F0F0F0' },
|
||||
title: { fontSize: 28, fontWeight: '700', color: Colors.textDark },
|
||||
content: { flex: 1, padding: Spacing.xl },
|
||||
lockedCard: { backgroundColor: Colors.card, padding: Spacing.xxxl, borderRadius: BorderRadius.xlarge, alignItems: 'center', ...Shadow.soft },
|
||||
lockedTitle: { fontSize: 24, fontWeight: '700', color: Colors.textDark, marginTop: Spacing.lg },
|
||||
lockedSubtitle: { fontSize: 16, color: Colors.textGray, marginTop: Spacing.sm, textAlign: 'center', lineHeight: 24 },
|
||||
requirementsCard: { backgroundColor: Colors.teal + '20', padding: Spacing.xl, borderRadius: BorderRadius.large, marginTop: Spacing.xl },
|
||||
requirementsTitle: { fontSize: 18, fontWeight: '600', color: Colors.textDark, marginBottom: Spacing.md },
|
||||
requirementItem: { flexDirection: 'row', alignItems: 'center', marginTop: Spacing.sm, gap: Spacing.sm },
|
||||
requirementText: { fontSize: 16, color: Colors.textDark },
|
||||
completeButton: { flexDirection: 'row', backgroundColor: Colors.teal, borderRadius: BorderRadius.xxlarge, paddingVertical: Spacing.lg, paddingHorizontal: Spacing.xxxl, alignItems: 'center', justifyContent: 'center', marginTop: Spacing.xl, gap: Spacing.sm, ...Shadow.soft },
|
||||
completeButtonText: { fontSize: 18, fontWeight: '600', color: '#FFFFFF' },
|
||||
citizenBadge: { flexDirection: 'row', alignItems: 'center', backgroundColor: Colors.mint + '20', paddingVertical: Spacing.sm, paddingHorizontal: Spacing.md, borderRadius: BorderRadius.large, marginTop: Spacing.sm, gap: Spacing.xs, alignSelf: 'flex-start' },
|
||||
citizenBadgeText: { fontSize: 14, fontWeight: '600', color: Colors.mint },
|
||||
sectionTitle: { fontSize: 20, fontWeight: '600', color: Colors.textDark, marginBottom: Spacing.md },
|
||||
comingSoon: { fontSize: 16, color: Colors.textGray, textAlign: 'center', marginTop: Spacing.xl },
|
||||
});
|
||||
@@ -1,320 +0,0 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
Alert,
|
||||
} from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import Colors from '../../constants/colors';
|
||||
import { Typography, Spacing, BorderRadius, Shadow } from '../../constants/theme';
|
||||
|
||||
interface Ministry {
|
||||
id: string;
|
||||
name: string;
|
||||
nameKu: string;
|
||||
icon: keyof typeof Ionicons.glyphMap;
|
||||
color: string;
|
||||
description: string;
|
||||
minister?: string;
|
||||
}
|
||||
|
||||
export default function MinistriesScreen({ navigation }: any) {
|
||||
const ministries: Ministry[] = [
|
||||
{
|
||||
id: 'finance',
|
||||
name: 'Finance',
|
||||
nameKu: 'Maliye',
|
||||
icon: 'cash',
|
||||
color: '#F39C12',
|
||||
description: 'Treasury, Budget & Economic Policy',
|
||||
minister: 'Dr. Heval Azad',
|
||||
},
|
||||
{
|
||||
id: 'justice',
|
||||
name: 'Justice',
|
||||
nameKu: 'Adalet',
|
||||
icon: 'scale',
|
||||
color: '#34495E',
|
||||
description: 'Legal System & Courts',
|
||||
minister: 'Av. Leyla Şoreş',
|
||||
},
|
||||
{
|
||||
id: 'health',
|
||||
name: 'Health',
|
||||
nameKu: 'Tenduristî',
|
||||
icon: 'medical',
|
||||
color: '#E91E63',
|
||||
description: 'Healthcare Services & Public Health',
|
||||
minister: 'Dr. Roj Berxwedan',
|
||||
},
|
||||
{
|
||||
id: 'education',
|
||||
name: 'Education',
|
||||
nameKu: 'Perwerde',
|
||||
icon: 'school',
|
||||
color: '#5C6BC0',
|
||||
description: 'Education System & Universities',
|
||||
minister: 'Prof. Aram Zana',
|
||||
},
|
||||
{
|
||||
id: 'commerce',
|
||||
name: 'Commerce',
|
||||
nameKu: 'Bazirganî',
|
||||
icon: 'cart',
|
||||
color: '#26A69A',
|
||||
description: 'Trade, Business & Industry',
|
||||
minister: 'Berivan Qazi',
|
||||
},
|
||||
{
|
||||
id: 'media',
|
||||
name: 'Media & Communications',
|
||||
nameKu: 'Medya û Ragihandin',
|
||||
icon: 'newspaper',
|
||||
color: '#FF9800',
|
||||
description: 'Press, Broadcasting & Information',
|
||||
minister: 'Jiyan Newroz',
|
||||
},
|
||||
{
|
||||
id: 'culture',
|
||||
name: 'Culture & Arts',
|
||||
nameKu: 'Çand û Huner',
|
||||
icon: 'color-palette',
|
||||
color: '#EC407A',
|
||||
description: 'Cultural Heritage & Arts',
|
||||
minister: 'Şêrko Dilan',
|
||||
},
|
||||
{
|
||||
id: 'tourism',
|
||||
name: 'Tourism',
|
||||
nameKu: 'Gerîyan',
|
||||
icon: 'airplane',
|
||||
color: '#00ACC1',
|
||||
description: 'Tourism Development & Promotion',
|
||||
minister: 'Azad Çiya',
|
||||
},
|
||||
{
|
||||
id: 'foreign',
|
||||
name: 'Foreign Affairs',
|
||||
nameKu: 'Karûbarên Derve',
|
||||
icon: 'globe',
|
||||
color: '#7E57C2',
|
||||
description: 'International Relations & Diplomacy',
|
||||
minister: 'Dilşa Rojava',
|
||||
},
|
||||
{
|
||||
id: 'interior',
|
||||
name: 'Interior',
|
||||
nameKu: 'Karûbarên Navxwe',
|
||||
icon: 'shield',
|
||||
color: '#8D6E63',
|
||||
description: 'Internal Security & Public Order',
|
||||
minister: 'Baran Zagros',
|
||||
},
|
||||
{
|
||||
id: 'defense',
|
||||
name: 'Defense',
|
||||
nameKu: 'Bergiranî',
|
||||
icon: 'shield-checkmark',
|
||||
color: '#455A64',
|
||||
description: 'National Defense & Security',
|
||||
minister: 'Gen. Kendal Şoreş',
|
||||
},
|
||||
{
|
||||
id: 'agriculture',
|
||||
name: 'Agriculture',
|
||||
nameKu: 'Çandinî',
|
||||
icon: 'leaf',
|
||||
color: '#8BC34A',
|
||||
description: 'Farming, Food Security & Rural Development',
|
||||
minister: 'Hêvî Berxwedan',
|
||||
},
|
||||
{
|
||||
id: 'environment',
|
||||
name: 'Environment',
|
||||
nameKu: 'Jîngeha',
|
||||
icon: 'earth',
|
||||
color: '#66BB6A',
|
||||
description: 'Environmental Protection & Climate',
|
||||
minister: 'Çiya Newroz',
|
||||
},
|
||||
{
|
||||
id: 'energy',
|
||||
name: 'Energy',
|
||||
nameKu: 'Wize',
|
||||
icon: 'flash',
|
||||
color: '#FFA726',
|
||||
description: 'Energy Resources & Infrastructure',
|
||||
minister: 'Roj Azad',
|
||||
},
|
||||
{
|
||||
id: 'transport',
|
||||
name: 'Transport',
|
||||
nameKu: 'Veguhestin',
|
||||
icon: 'car',
|
||||
color: '#42A5F5',
|
||||
description: 'Transportation & Infrastructure',
|
||||
minister: 'Beritan Qazi',
|
||||
},
|
||||
{
|
||||
id: 'labor',
|
||||
name: 'Labor & Social Affairs',
|
||||
nameKu: 'Kar û Karûbarên Civakî',
|
||||
icon: 'people',
|
||||
color: '#AB47BC',
|
||||
description: 'Employment & Social Welfare',
|
||||
minister: 'Heval Dilan',
|
||||
},
|
||||
];
|
||||
|
||||
const handleMinistryPress = (ministry: Ministry) => {
|
||||
Alert.alert(
|
||||
ministry.name,
|
||||
`${ministry.nameKu}\n\nMinister: ${ministry.minister}\n\n${ministry.description}\n\nThis feature is under development.`,
|
||||
[{ text: 'OK' }]
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
{/* Header */}
|
||||
<View style={styles.header}>
|
||||
<TouchableOpacity onPress={() => navigation.goBack()} style={styles.backButton}>
|
||||
<Ionicons name="arrow-back" size={24} color={Colors.textDark} />
|
||||
</TouchableOpacity>
|
||||
<View style={styles.headerContent}>
|
||||
<Text style={styles.headerTitle}>Ministries</Text>
|
||||
<Text style={styles.headerSubtitle}>Wezaretî</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<ScrollView style={styles.content} showsVerticalScrollIndicator={false}>
|
||||
{/* Ministries Grid */}
|
||||
<View style={styles.grid}>
|
||||
{ministries.map((ministry) => (
|
||||
<TouchableOpacity
|
||||
key={ministry.id}
|
||||
style={styles.ministryCard}
|
||||
onPress={() => handleMinistryPress(ministry)}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<View style={[styles.iconContainer, { backgroundColor: ministry.color }]}>
|
||||
<Ionicons name={ministry.icon} size={32} color="#FFFFFF" />
|
||||
</View>
|
||||
<Text style={styles.ministryName}>{ministry.name}</Text>
|
||||
<Text style={styles.ministryNameKu}>{ministry.nameKu}</Text>
|
||||
{ministry.minister && (
|
||||
<Text style={styles.ministerName}>{ministry.minister}</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
|
||||
{/* Info Footer */}
|
||||
<View style={styles.infoFooter}>
|
||||
<Ionicons name="information-circle" size={20} color={Colors.primary} />
|
||||
<Text style={styles.infoText}>
|
||||
Cabinet of {ministries.length} ministries serving the people of Kurdistan.
|
||||
</Text>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.background,
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#FFFFFF',
|
||||
paddingHorizontal: Spacing.lg,
|
||||
paddingVertical: Spacing.md,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#E0E0E0',
|
||||
...Shadow.small,
|
||||
},
|
||||
backButton: {
|
||||
marginRight: Spacing.md,
|
||||
},
|
||||
headerContent: {
|
||||
flex: 1,
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: Typography.sizes.xxl,
|
||||
fontWeight: Typography.weights.bold,
|
||||
color: Colors.textDark,
|
||||
},
|
||||
headerSubtitle: {
|
||||
fontSize: Typography.sizes.md,
|
||||
color: Colors.textLight,
|
||||
marginTop: Spacing.xs,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
},
|
||||
grid: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
padding: Spacing.md,
|
||||
},
|
||||
ministryCard: {
|
||||
width: '31%',
|
||||
marginHorizontal: '1%',
|
||||
marginBottom: Spacing.lg,
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: BorderRadius.lg,
|
||||
padding: Spacing.md,
|
||||
alignItems: 'center',
|
||||
...Shadow.small,
|
||||
},
|
||||
iconContainer: {
|
||||
width: 64,
|
||||
height: 64,
|
||||
borderRadius: BorderRadius.lg,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginBottom: Spacing.sm,
|
||||
},
|
||||
ministryName: {
|
||||
fontSize: Typography.sizes.xs,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.textDark,
|
||||
textAlign: 'center',
|
||||
marginBottom: Spacing.xs,
|
||||
},
|
||||
ministryNameKu: {
|
||||
fontSize: Typography.sizes.xs,
|
||||
color: Colors.textLight,
|
||||
textAlign: 'center',
|
||||
marginBottom: Spacing.xs,
|
||||
},
|
||||
ministerName: {
|
||||
fontSize: 10,
|
||||
color: Colors.primary,
|
||||
textAlign: 'center',
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
infoFooter: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#E3F2FD',
|
||||
margin: Spacing.lg,
|
||||
padding: Spacing.md,
|
||||
borderRadius: BorderRadius.md,
|
||||
},
|
||||
infoText: {
|
||||
flex: 1,
|
||||
fontSize: Typography.sizes.sm,
|
||||
color: Colors.primary,
|
||||
marginLeft: Spacing.sm,
|
||||
lineHeight: 18,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,383 +0,0 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
ScrollView,
|
||||
SafeAreaView,
|
||||
ActivityIndicator,
|
||||
} from 'react-native';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import Colors from '../../constants/colors';
|
||||
import { Typography, Spacing, BorderRadius, Shadow, IconSizes } from '../../constants/theme';
|
||||
import { usePolkadot } from '../../contexts/PolkadotContext';
|
||||
import pezkuwiAPI from '../../services/api';
|
||||
|
||||
interface QuickAction {
|
||||
id: string;
|
||||
label: string;
|
||||
icon: keyof typeof Ionicons.glyphMap;
|
||||
color: string;
|
||||
onPress: () => void;
|
||||
}
|
||||
|
||||
export default function HomeScreen({ navigation }: any) {
|
||||
const { selectedAccount } = usePolkadot();
|
||||
const [balance, setBalance] = useState<any>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [trustScore] = useState(750);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedAccount) {
|
||||
loadBalance();
|
||||
}
|
||||
}, [selectedAccount]);
|
||||
|
||||
const loadBalance = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
if (selectedAccount?.address) {
|
||||
const balanceData = await pezkuwiAPI.getBalance(selectedAccount.address);
|
||||
setBalance(balanceData);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading balance:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const quickActions: QuickAction[] = [
|
||||
{
|
||||
id: 'send',
|
||||
label: 'Send',
|
||||
icon: 'arrow-forward',
|
||||
color: Colors.coral,
|
||||
onPress: () => navigation.navigate('Send', { token: 'HEZ' }),
|
||||
},
|
||||
{
|
||||
id: 'receive',
|
||||
label: 'Receive',
|
||||
icon: 'arrow-down',
|
||||
color: Colors.blue,
|
||||
onPress: () => navigation.navigate('Receive', { token: 'HEZ' }),
|
||||
},
|
||||
{
|
||||
id: 'vote',
|
||||
label: 'Vote',
|
||||
icon: 'checkmark-circle',
|
||||
color: Colors.mint,
|
||||
onPress: () => navigation.navigate('Governance'),
|
||||
},
|
||||
{
|
||||
id: 'proposals',
|
||||
label: 'Proposals',
|
||||
icon: 'bulb',
|
||||
color: Colors.peach,
|
||||
onPress: () => navigation.navigate('Governance'),
|
||||
},
|
||||
{
|
||||
id: 'identity',
|
||||
label: 'Identity',
|
||||
icon: 'person',
|
||||
color: Colors.teal,
|
||||
onPress: () => navigation.navigate('Identity'),
|
||||
},
|
||||
{
|
||||
id: 'certificates',
|
||||
label: 'Certificates',
|
||||
icon: 'school',
|
||||
color: Colors.gold,
|
||||
onPress: () => navigation.navigate('Education'),
|
||||
},
|
||||
{
|
||||
id: 'exchange',
|
||||
label: 'Exchange',
|
||||
icon: 'swap-horizontal',
|
||||
color: Colors.cyan,
|
||||
onPress: () => navigation.navigate('Exchange'),
|
||||
},
|
||||
{
|
||||
id: 'rewards',
|
||||
label: 'Rewards',
|
||||
icon: 'star',
|
||||
color: Colors.lavender,
|
||||
onPress: () => navigation.navigate('Wallet'),
|
||||
},
|
||||
{
|
||||
id: 'trust',
|
||||
label: 'Trust',
|
||||
icon: 'heart',
|
||||
color: Colors.emerald,
|
||||
onPress: () => navigation.navigate('Profile'),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<ScrollView showsVerticalScrollIndicator={false}>
|
||||
{/* Header */}
|
||||
<LinearGradient
|
||||
colors={Colors.gradients.header}
|
||||
style={styles.header}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
>
|
||||
<View style={styles.headerTop}>
|
||||
{/* Profile Avatar */}
|
||||
<TouchableOpacity
|
||||
style={styles.profileSection}
|
||||
onPress={() => navigation.navigate('Profile')}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<View style={styles.avatar}>
|
||||
<Ionicons name="person" size={24} color="#FFFFFF" />
|
||||
</View>
|
||||
|
||||
{/* Trust Score Badge */}
|
||||
<TouchableOpacity
|
||||
style={styles.trustBadge}
|
||||
onPress={() => navigation.navigate('TrustScore')}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Ionicons name="star" size={12} color="#FFFFFF" />
|
||||
<Text style={styles.trustScore}>{trustScore}</Text>
|
||||
</TouchableOpacity>
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* Action Icons */}
|
||||
<View style={styles.headerActions}>
|
||||
<TouchableOpacity
|
||||
style={styles.headerIcon}
|
||||
onPress={() => navigation.navigate('QRScanner')}
|
||||
>
|
||||
<Ionicons name="qr-code-outline" size={24} color="#FFFFFF" />
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.headerIcon}
|
||||
onPress={() => navigation.navigate('Notifications')}
|
||||
>
|
||||
<Ionicons name="notifications-outline" size={24} color="#FFFFFF" />
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.headerIcon}
|
||||
onPress={() => navigation.navigate('Profile')}
|
||||
>
|
||||
<Ionicons name="settings-outline" size={24} color="#FFFFFF" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
|
||||
{/* Balance Card */}
|
||||
<View style={styles.balanceCardContainer}>
|
||||
<TouchableOpacity
|
||||
style={styles.balanceCard}
|
||||
onPress={() => navigation.navigate('Wallet')}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
{loading ? (
|
||||
<View style={styles.loadingContainer}>
|
||||
<ActivityIndicator size="large" color={Colors.coral} />
|
||||
<Text style={styles.loadingText}>Loading balance...</Text>
|
||||
</View>
|
||||
) : (
|
||||
<View style={styles.balanceRow}>
|
||||
<TouchableOpacity
|
||||
style={styles.balanceItem}
|
||||
onPress={() => navigation.navigate('Wallet', { tab: 'HEZ' })}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Text style={styles.balanceLabel}>HEZ Balance</Text>
|
||||
<Text style={styles.balanceAmount}>{balance?.hez || '0.0000'}</Text>
|
||||
<View style={styles.underline} />
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.balanceItem}
|
||||
onPress={() => navigation.navigate('Wallet', { tab: 'PEZ' })}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Text style={styles.balanceLabel}>PEZ Balance</Text>
|
||||
<Text style={styles.balanceAmountSecondary}>{balance?.pez || '0.0000'}</Text>
|
||||
<View style={[styles.underline, { backgroundColor: Colors.peach }]} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Quick Actions */}
|
||||
<View style={styles.quickActionsSection}>
|
||||
<Text style={styles.sectionTitle}>Quick Actions</Text>
|
||||
|
||||
<View style={styles.quickActionsGrid}>
|
||||
{quickActions.map((action) => (
|
||||
<TouchableOpacity
|
||||
key={action.id}
|
||||
style={styles.quickActionButton}
|
||||
onPress={action.onPress}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<View style={[styles.quickActionIcon, { backgroundColor: action.color }]}>
|
||||
<Ionicons name={action.icon} size={24} color="#FFFFFF" />
|
||||
</View>
|
||||
<Text style={styles.quickActionLabel}>{action.label}</Text>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.background,
|
||||
},
|
||||
header: {
|
||||
paddingHorizontal: Spacing.xl,
|
||||
paddingTop: Spacing.xl,
|
||||
paddingBottom: Spacing.xxxl * 2,
|
||||
borderBottomLeftRadius: BorderRadius.xxlarge,
|
||||
borderBottomRightRadius: BorderRadius.xxlarge,
|
||||
},
|
||||
headerTop: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
},
|
||||
profileSection: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: Spacing.sm,
|
||||
},
|
||||
avatar: {
|
||||
width: 50,
|
||||
height: 50,
|
||||
borderRadius: 25,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.3)',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
trustBadge: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: Colors.gold,
|
||||
paddingHorizontal: Spacing.md,
|
||||
paddingVertical: Spacing.xs,
|
||||
borderRadius: BorderRadius.round,
|
||||
gap: Spacing.xs,
|
||||
},
|
||||
trustScore: {
|
||||
fontSize: Typography.sizes.body,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: '#FFFFFF',
|
||||
},
|
||||
headerActions: {
|
||||
flexDirection: 'row',
|
||||
gap: Spacing.md,
|
||||
},
|
||||
headerIcon: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.2)',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
balanceCardContainer: {
|
||||
paddingHorizontal: Spacing.xl,
|
||||
marginTop: -Spacing.xxxl,
|
||||
},
|
||||
balanceCard: {
|
||||
backgroundColor: '#F5F3FF',
|
||||
borderRadius: BorderRadius.large,
|
||||
padding: Spacing.xl,
|
||||
...Shadow.soft,
|
||||
},
|
||||
balanceRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
balanceItem: {
|
||||
flex: 1,
|
||||
},
|
||||
balanceLabel: {
|
||||
fontSize: Typography.sizes.body,
|
||||
color: Colors.textGray,
|
||||
marginBottom: Spacing.xs,
|
||||
},
|
||||
balanceAmount: {
|
||||
fontSize: Typography.sizes.hero,
|
||||
fontWeight: Typography.weights.bold,
|
||||
color: Colors.textDark,
|
||||
marginBottom: Spacing.xs,
|
||||
},
|
||||
balanceAmountSecondary: {
|
||||
fontSize: Typography.sizes.heading,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.textDark,
|
||||
marginBottom: Spacing.xs,
|
||||
},
|
||||
loadingContainer: {
|
||||
padding: Spacing.xxl,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
loadingText: {
|
||||
marginTop: Spacing.md,
|
||||
fontSize: Typography.sizes.medium,
|
||||
color: Colors.textGray,
|
||||
},
|
||||
underline: {
|
||||
width: 80,
|
||||
height: 3,
|
||||
backgroundColor: Colors.teal,
|
||||
borderRadius: 2,
|
||||
},
|
||||
quickActionsSection: {
|
||||
paddingHorizontal: Spacing.xl,
|
||||
marginTop: Spacing.xl,
|
||||
marginBottom: Spacing.xl,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: Typography.sizes.large,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.textDark,
|
||||
marginBottom: Spacing.lg,
|
||||
},
|
||||
quickActionsGrid: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
gap: Spacing.md,
|
||||
},
|
||||
quickActionButton: {
|
||||
width: '31%',
|
||||
backgroundColor: Colors.card,
|
||||
borderRadius: BorderRadius.large,
|
||||
padding: Spacing.lg,
|
||||
alignItems: 'center',
|
||||
...Shadow.soft,
|
||||
},
|
||||
quickActionIcon: {
|
||||
width: IconSizes.xxlarge,
|
||||
height: IconSizes.xxlarge,
|
||||
borderRadius: IconSizes.xxlarge / 2,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginBottom: Spacing.sm,
|
||||
},
|
||||
quickActionLabel: {
|
||||
fontSize: Typography.sizes.small,
|
||||
color: Colors.textGray,
|
||||
textAlign: 'center',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,292 +0,0 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
ActivityIndicator,
|
||||
} from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import Colors from '../../constants/colors';
|
||||
import { Typography, Spacing, BorderRadius, Shadow } from '../../constants/theme';
|
||||
|
||||
interface Notification {
|
||||
id: string;
|
||||
type: 'transaction' | 'governance' | 'reward' | 'system';
|
||||
title: string;
|
||||
message: string;
|
||||
timestamp: number;
|
||||
read: boolean;
|
||||
}
|
||||
|
||||
export default function NotificationsScreen({ navigation }: any) {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [notifications, setNotifications] = useState<Notification[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
loadNotifications();
|
||||
}, []);
|
||||
|
||||
const loadNotifications = async () => {
|
||||
// Mock data - replace with actual API call
|
||||
setTimeout(() => {
|
||||
setNotifications([
|
||||
{
|
||||
id: '1',
|
||||
type: 'transaction',
|
||||
title: 'Transaction Confirmed',
|
||||
message: 'You received 1,000 PEZ from 5Grw...KutQY',
|
||||
timestamp: Date.now() - 3600000,
|
||||
read: false,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'governance',
|
||||
title: 'New Proposal',
|
||||
message: 'Proposal #47: Increase PEZ rewards by 10%',
|
||||
timestamp: Date.now() - 7200000,
|
||||
read: false,
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
type: 'reward',
|
||||
title: 'Staking Rewards',
|
||||
message: 'You earned 245 PEZ from staking',
|
||||
timestamp: Date.now() - 86400000,
|
||||
read: true,
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
type: 'system',
|
||||
title: 'KYC Approved',
|
||||
message: 'Your Kurdistan Citizen Card is ready',
|
||||
timestamp: Date.now() - 172800000,
|
||||
read: true,
|
||||
},
|
||||
]);
|
||||
setLoading(false);
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
const getNotificationIcon = (type: string) => {
|
||||
switch (type) {
|
||||
case 'transaction':
|
||||
return 'swap-horizontal';
|
||||
case 'governance':
|
||||
return 'megaphone';
|
||||
case 'reward':
|
||||
return 'star';
|
||||
case 'system':
|
||||
return 'information-circle';
|
||||
default:
|
||||
return 'notifications';
|
||||
}
|
||||
};
|
||||
|
||||
const getNotificationColor = (type: string) => {
|
||||
switch (type) {
|
||||
case 'transaction':
|
||||
return Colors.blue;
|
||||
case 'governance':
|
||||
return Colors.peach;
|
||||
case 'reward':
|
||||
return Colors.gold;
|
||||
case 'system':
|
||||
return Colors.teal;
|
||||
default:
|
||||
return Colors.textGray;
|
||||
}
|
||||
};
|
||||
|
||||
const formatTime = (timestamp: number) => {
|
||||
const date = new Date(timestamp);
|
||||
const now = new Date();
|
||||
const diff = now.getTime() - date.getTime();
|
||||
const hours = Math.floor(diff / (1000 * 60 * 60));
|
||||
const days = Math.floor(hours / 24);
|
||||
|
||||
if (hours < 1) return 'Just now';
|
||||
if (hours < 24) return `${hours}h ago`;
|
||||
if (days === 1) return 'Yesterday';
|
||||
return `${days}d ago`;
|
||||
};
|
||||
|
||||
const markAsRead = (id: string) => {
|
||||
setNotifications((prev) =>
|
||||
prev.map((notif) => (notif.id === id ? { ...notif, read: true } : notif))
|
||||
);
|
||||
};
|
||||
|
||||
const unreadCount = notifications.filter((n) => !n.read).length;
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<View style={styles.header}>
|
||||
<TouchableOpacity onPress={() => navigation.goBack()} style={styles.backButton}>
|
||||
<Ionicons name="arrow-back" size={24} color={Colors.textDark} />
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.headerTitle}>Notifications</Text>
|
||||
{unreadCount > 0 && (
|
||||
<View style={styles.badge}>
|
||||
<Text style={styles.badgeText}>{unreadCount}</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<ScrollView style={styles.content} showsVerticalScrollIndicator={false}>
|
||||
{loading ? (
|
||||
<ActivityIndicator size="large" color={Colors.teal} style={{ marginTop: 50 }} />
|
||||
) : notifications.length === 0 ? (
|
||||
<View style={styles.emptyState}>
|
||||
<Ionicons name="notifications-off-outline" size={80} color={Colors.textGray} />
|
||||
<Text style={styles.emptyText}>No notifications yet</Text>
|
||||
</View>
|
||||
) : (
|
||||
notifications.map((notification) => (
|
||||
<TouchableOpacity
|
||||
key={notification.id}
|
||||
style={[
|
||||
styles.notificationCard,
|
||||
!notification.read && styles.unreadCard,
|
||||
]}
|
||||
onPress={() => markAsRead(notification.id)}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<View
|
||||
style={[
|
||||
styles.iconContainer,
|
||||
{ backgroundColor: getNotificationColor(notification.type) + '20' },
|
||||
]}
|
||||
>
|
||||
<Ionicons
|
||||
name={getNotificationIcon(notification.type)}
|
||||
size={24}
|
||||
color={getNotificationColor(notification.type)}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.notificationContent}>
|
||||
<View style={styles.notificationHeader}>
|
||||
<Text style={styles.notificationTitle}>{notification.title}</Text>
|
||||
{!notification.read && <View style={styles.unreadDot} />}
|
||||
</View>
|
||||
<Text style={styles.notificationMessage}>{notification.message}</Text>
|
||||
<Text style={styles.notificationTime}>{formatTime(notification.timestamp)}</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
))
|
||||
)}
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.background,
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: Spacing.xl,
|
||||
paddingVertical: Spacing.lg,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#F0F0F0',
|
||||
},
|
||||
backButton: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: Colors.card,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginRight: Spacing.md,
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: Typography.sizes.large,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.textDark,
|
||||
flex: 1,
|
||||
},
|
||||
badge: {
|
||||
backgroundColor: Colors.coral,
|
||||
width: 24,
|
||||
height: 24,
|
||||
borderRadius: 12,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
badgeText: {
|
||||
fontSize: 12,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: '#FFFFFF',
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
padding: Spacing.lg,
|
||||
},
|
||||
notificationCard: {
|
||||
flexDirection: 'row',
|
||||
backgroundColor: Colors.card,
|
||||
padding: Spacing.lg,
|
||||
borderRadius: BorderRadius.large,
|
||||
marginBottom: Spacing.md,
|
||||
...Shadow.small,
|
||||
},
|
||||
unreadCard: {
|
||||
borderLeftWidth: 4,
|
||||
borderLeftColor: Colors.teal,
|
||||
},
|
||||
iconContainer: {
|
||||
width: 50,
|
||||
height: 50,
|
||||
borderRadius: 25,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginRight: Spacing.md,
|
||||
},
|
||||
notificationContent: {
|
||||
flex: 1,
|
||||
},
|
||||
notificationHeader: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginBottom: 4,
|
||||
},
|
||||
notificationTitle: {
|
||||
fontSize: Typography.sizes.medium,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.textDark,
|
||||
flex: 1,
|
||||
},
|
||||
unreadDot: {
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: 4,
|
||||
backgroundColor: Colors.teal,
|
||||
},
|
||||
notificationMessage: {
|
||||
fontSize: Typography.sizes.small,
|
||||
color: Colors.textGray,
|
||||
marginBottom: 4,
|
||||
},
|
||||
notificationTime: {
|
||||
fontSize: Typography.sizes.small,
|
||||
color: Colors.textGray,
|
||||
opacity: 0.7,
|
||||
},
|
||||
emptyState: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginTop: 100,
|
||||
},
|
||||
emptyText: {
|
||||
fontSize: Typography.sizes.medium,
|
||||
color: Colors.textGray,
|
||||
marginTop: Spacing.lg,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,459 +0,0 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
SafeAreaView,
|
||||
Image,
|
||||
ActivityIndicator,
|
||||
ScrollView,
|
||||
} from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import QRCode from 'react-native-qrcode-svg';
|
||||
import Colors from '../../constants/colors';
|
||||
import { Typography, Spacing, BorderRadius, Shadow } from '../../constants/theme';
|
||||
import { kycService } from '../../services/kycService';
|
||||
import { KurdistanCitizen, REGION_LABELS } from '../../types/kyc';
|
||||
|
||||
export default function CitizenCardScreen({ navigation }: any) {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [citizen, setCitizen] = useState<KurdistanCitizen | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
loadCitizen();
|
||||
}, []);
|
||||
|
||||
const loadCitizen = async () => {
|
||||
try {
|
||||
const data = await kycService.getCitizen();
|
||||
setCitizen(data);
|
||||
} catch (error) {
|
||||
console.error('Failed to load citizen data:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<ActivityIndicator size="large" color={Colors.teal} />
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
if (!citizen) {
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<Text style={styles.errorText}>No citizen data found</Text>
|
||||
<TouchableOpacity
|
||||
style={styles.button}
|
||||
onPress={() => navigation.navigate('IdentityKYCForm')}
|
||||
>
|
||||
<Text style={styles.buttonText}>Complete KYC</Text>
|
||||
</TouchableOpacity>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const formatDate = (timestamp: number) => {
|
||||
const date = new Date(timestamp);
|
||||
return date.toLocaleDateString('en-GB');
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<View style={styles.header}>
|
||||
<TouchableOpacity onPress={() => navigation.goBack()} style={styles.backButton}>
|
||||
<Ionicons name="arrow-back" size={24} color={Colors.textDark} />
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.headerTitle}>Digital Hemwelatî</Text>
|
||||
<TouchableOpacity style={styles.shareButton}>
|
||||
<Ionicons name="share-outline" size={24} color={Colors.textDark} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<ScrollView style={styles.content} showsVerticalScrollIndicator={false}>
|
||||
{/* Official Citizen Card */}
|
||||
<View style={styles.card}>
|
||||
{/* Burgundy Header */}
|
||||
<View style={styles.cardHeader}>
|
||||
<Text style={styles.headerText1}>KOMARA KURDISTANÊ</Text>
|
||||
<Text style={styles.headerText2}>HEMWELATÎ</Text>
|
||||
</View>
|
||||
|
||||
{/* Main Content - White Background */}
|
||||
<View style={styles.cardBody}>
|
||||
{/* Photo and Info Section */}
|
||||
<View style={styles.topSection}>
|
||||
{/* Photo */}
|
||||
<View style={styles.photoContainer}>
|
||||
{citizen.photo ? (
|
||||
<Image source={{ uri: citizen.photo }} style={styles.photo} />
|
||||
) : (
|
||||
<View style={styles.photoPlaceholder}>
|
||||
<Ionicons name="person" size={50} color="#999" />
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* Info List */}
|
||||
<View style={styles.infoList}>
|
||||
<View style={styles.infoRow}>
|
||||
<Text style={styles.infoLabel}>NAV/NAME</Text>
|
||||
<Text style={styles.infoValue}>{citizen.fullName}</Text>
|
||||
</View>
|
||||
|
||||
{citizen.fatherName && (
|
||||
<View style={styles.infoRow}>
|
||||
<Text style={styles.infoLabel}>BAV/FATHER</Text>
|
||||
<Text style={styles.infoValue}>{citizen.fatherName}</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{citizen.grandfatherName && (
|
||||
<View style={styles.infoRow}>
|
||||
<Text style={styles.infoLabel}>DAPÎR/GRANDFATHER</Text>
|
||||
<Text style={styles.infoValue}>{citizen.grandfatherName}</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{citizen.greatGrandfatherName && (
|
||||
<View style={styles.infoRow}>
|
||||
<Text style={styles.infoLabel}>DAPÎRA BIRA/G.GRANDFATHER</Text>
|
||||
<Text style={styles.infoValue}>{citizen.greatGrandfatherName}</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{citizen.motherName && (
|
||||
<View style={styles.infoRow}>
|
||||
<Text style={styles.infoLabel}>DAY/MOTHER</Text>
|
||||
<Text style={styles.infoValue}>{citizen.motherName}</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
<View style={styles.infoRow}>
|
||||
<Text style={styles.infoLabel}>ZEWICÎN/MARITAL</Text>
|
||||
<Text style={styles.infoValue}>
|
||||
{citizen.maritalStatus === 'married' ? 'Zewicî' : 'Nezewicî'}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{citizen.maritalStatus === 'married' && citizen.spouseName && (
|
||||
<View style={styles.infoRow}>
|
||||
<Text style={styles.infoLabel}>HEVJÎN/SPOUSE</Text>
|
||||
<Text style={styles.infoValue}>{citizen.spouseName}</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{citizen.children && citizen.children.length > 0 && (
|
||||
<View style={styles.infoRow}>
|
||||
<Text style={styles.infoLabel}>ZAROK/CHILDREN</Text>
|
||||
<Text style={styles.infoValue}>{citizen.children.length}</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* PEZ Sun Logo */}
|
||||
<View style={styles.sunContainer}>
|
||||
<Ionicons name="sunny" size={80} color="#D4A017" />
|
||||
</View>
|
||||
|
||||
{/* Region and Citizen ID */}
|
||||
<View style={styles.middleSection}>
|
||||
<View style={styles.regionRow}>
|
||||
<Text style={styles.regionLabel}>HEREM/REGION</Text>
|
||||
<Text style={styles.regionValue}>{REGION_LABELS[citizen.region].en}</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.citizenIdRow}>
|
||||
<Text style={styles.citizenIdLabel}>JIMARA HEMWELATÎ/CITIZEN ID</Text>
|
||||
<Text style={styles.citizenIdValue}>{citizen.citizenId}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Green Footer */}
|
||||
<View style={styles.cardFooter}>
|
||||
<View style={styles.footerLeft}>
|
||||
<View style={styles.footerRow}>
|
||||
<Text style={styles.footerLabel}>NASNAMA DIJÎTAL/DIGITAL ID</Text>
|
||||
<Text style={styles.footerValue}>{citizen.citizenId.replace(/-/g, '')}</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.footerRow}>
|
||||
<Text style={styles.footerLabel}>JIMARA VEKIRAN/ACCOUNT#</Text>
|
||||
<Text style={styles.footerValue}>{citizen.qrCode.substring(0, 12)}</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.footerRow}>
|
||||
<Text style={styles.footerLabel}>DAXWAZ/ISSUED</Text>
|
||||
<Text style={styles.footerValue}>{formatDate(citizen.approvedAt)}</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.footerRight}>
|
||||
<QRCode value={citizen.qrCode} size={70} backgroundColor="transparent" color="#FFFFFF" />
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Status Badge */}
|
||||
<View style={styles.statusBadge}>
|
||||
<Ionicons name="checkmark-circle" size={24} color={Colors.mint} />
|
||||
<Text style={styles.statusText}>Verified Kurdistan Citizen</Text>
|
||||
</View>
|
||||
|
||||
{/* Info Text */}
|
||||
<Text style={styles.infoText}>
|
||||
This official digital citizenship card grants you full access to Governance (Welati) and all citizen-only features on PezkuwiChain.
|
||||
</Text>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<View style={styles.actions}>
|
||||
<TouchableOpacity style={styles.actionButton}>
|
||||
<Ionicons name="download-outline" size={24} color={Colors.teal} />
|
||||
<Text style={styles.actionText}>Download</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity style={styles.actionButton}>
|
||||
<Ionicons name="qr-code-outline" size={24} color={Colors.teal} />
|
||||
<Text style={styles.actionText}>Show QR</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity style={styles.actionButton}>
|
||||
<Ionicons name="share-social-outline" size={24} color={Colors.teal} />
|
||||
<Text style={styles.actionText}>Share</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.background,
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: Spacing.xl,
|
||||
paddingVertical: Spacing.lg,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#F0F0F0',
|
||||
},
|
||||
backButton: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: Colors.card,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
shareButton: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: Colors.card,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: Typography.sizes.large,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.textDark,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
padding: Spacing.xl,
|
||||
},
|
||||
card: {
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: BorderRadius.xlarge,
|
||||
overflow: 'hidden',
|
||||
...Shadow.medium,
|
||||
},
|
||||
cardHeader: {
|
||||
backgroundColor: '#8B1538', // Burgundy
|
||||
paddingVertical: Spacing.xl,
|
||||
alignItems: 'center',
|
||||
},
|
||||
headerText1: {
|
||||
fontSize: 20,
|
||||
fontWeight: '700',
|
||||
color: '#D4A017', // Gold
|
||||
letterSpacing: 1,
|
||||
},
|
||||
headerText2: {
|
||||
fontSize: 24,
|
||||
fontWeight: '700',
|
||||
color: '#FFFFFF',
|
||||
letterSpacing: 2,
|
||||
marginTop: 4,
|
||||
},
|
||||
cardBody: {
|
||||
backgroundColor: '#FFFFFF',
|
||||
padding: Spacing.lg,
|
||||
},
|
||||
topSection: {
|
||||
flexDirection: 'row',
|
||||
marginBottom: Spacing.md,
|
||||
},
|
||||
photoContainer: {
|
||||
width: 100,
|
||||
height: 100,
|
||||
borderRadius: 50,
|
||||
overflow: 'hidden',
|
||||
backgroundColor: '#D0D0D0',
|
||||
marginRight: Spacing.md,
|
||||
},
|
||||
photo: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
photoPlaceholder: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#D0D0D0',
|
||||
},
|
||||
infoList: {
|
||||
flex: 1,
|
||||
},
|
||||
infoRow: {
|
||||
marginBottom: 6,
|
||||
},
|
||||
infoLabel: {
|
||||
fontSize: 9,
|
||||
fontWeight: '600',
|
||||
color: '#333',
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
infoValue: {
|
||||
fontSize: 11,
|
||||
fontWeight: '700',
|
||||
color: '#000',
|
||||
},
|
||||
sunContainer: {
|
||||
alignItems: 'center',
|
||||
marginVertical: Spacing.md,
|
||||
},
|
||||
middleSection: {
|
||||
marginTop: Spacing.sm,
|
||||
},
|
||||
regionRow: {
|
||||
marginBottom: Spacing.sm,
|
||||
},
|
||||
regionLabel: {
|
||||
fontSize: 11,
|
||||
fontWeight: '600',
|
||||
color: '#333',
|
||||
},
|
||||
regionValue: {
|
||||
fontSize: 13,
|
||||
fontWeight: '700',
|
||||
color: '#000',
|
||||
},
|
||||
citizenIdRow: {
|
||||
marginTop: Spacing.sm,
|
||||
},
|
||||
citizenIdLabel: {
|
||||
fontSize: 11,
|
||||
fontWeight: '600',
|
||||
color: '#333',
|
||||
},
|
||||
citizenIdValue: {
|
||||
fontSize: 15,
|
||||
fontWeight: '700',
|
||||
color: '#000',
|
||||
letterSpacing: 1,
|
||||
},
|
||||
cardFooter: {
|
||||
backgroundColor: '#007A3D', // Green
|
||||
flexDirection: 'row',
|
||||
padding: Spacing.lg,
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
footerLeft: {
|
||||
flex: 1,
|
||||
},
|
||||
footerRow: {
|
||||
marginBottom: 6,
|
||||
},
|
||||
footerLabel: {
|
||||
fontSize: 9,
|
||||
fontWeight: '600',
|
||||
color: '#FFFFFF',
|
||||
opacity: 0.9,
|
||||
},
|
||||
footerValue: {
|
||||
fontSize: 11,
|
||||
fontWeight: '700',
|
||||
color: '#D4A017', // Gold
|
||||
},
|
||||
footerRight: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
statusBadge: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: Colors.mint + '20',
|
||||
padding: Spacing.md,
|
||||
borderRadius: BorderRadius.large,
|
||||
marginTop: Spacing.xl,
|
||||
gap: Spacing.sm,
|
||||
},
|
||||
statusText: {
|
||||
fontSize: Typography.sizes.medium,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.mint,
|
||||
},
|
||||
infoText: {
|
||||
fontSize: Typography.sizes.small,
|
||||
color: Colors.textGray,
|
||||
textAlign: 'center',
|
||||
marginTop: Spacing.lg,
|
||||
lineHeight: 20,
|
||||
},
|
||||
actions: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-around',
|
||||
marginTop: Spacing.xl,
|
||||
marginBottom: Spacing.xl,
|
||||
},
|
||||
actionButton: {
|
||||
alignItems: 'center',
|
||||
gap: Spacing.sm,
|
||||
},
|
||||
actionText: {
|
||||
fontSize: Typography.sizes.small,
|
||||
color: Colors.teal,
|
||||
fontWeight: Typography.weights.medium,
|
||||
},
|
||||
errorText: {
|
||||
fontSize: Typography.sizes.medium,
|
||||
color: Colors.textGray,
|
||||
textAlign: 'center',
|
||||
},
|
||||
button: {
|
||||
backgroundColor: Colors.teal,
|
||||
paddingVertical: Spacing.lg,
|
||||
paddingHorizontal: Spacing.xxxl,
|
||||
borderRadius: BorderRadius.xxlarge,
|
||||
marginTop: Spacing.xl,
|
||||
},
|
||||
buttonText: {
|
||||
fontSize: Typography.sizes.medium,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: '#FFFFFF',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,435 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
ScrollView,
|
||||
SafeAreaView,
|
||||
Alert,
|
||||
ActivityIndicator,
|
||||
} from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { Picker } from '@react-native-picker/picker';
|
||||
import Colors from '../../constants/colors';
|
||||
import { Typography, Spacing, BorderRadius, Shadow } from '../../constants/theme';
|
||||
import { KYCFormData, Region, MaritalStatus, REGION_LABELS } from '../../types/kyc';
|
||||
import { kycService } from '../../services/kycService';
|
||||
|
||||
export default function IdentityKYCFormScreen({ navigation }: any) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [formData, setFormData] = useState<KYCFormData>({
|
||||
fullName: '',
|
||||
fatherName: '',
|
||||
grandfatherName: '',
|
||||
greatGrandfatherName: '',
|
||||
motherName: '',
|
||||
maritalStatus: 'single',
|
||||
region: 'basur',
|
||||
});
|
||||
|
||||
const updateField = (field: keyof KYCFormData, value: any) => {
|
||||
setFormData({ ...formData, [field]: value });
|
||||
};
|
||||
|
||||
const updateChild = (index: number, name: string) => {
|
||||
const children = formData.children || [];
|
||||
children[index] = { name, order: index + 1 };
|
||||
setFormData({ ...formData, children });
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
// Validation
|
||||
if (!formData.fullName || !formData.fatherName || !formData.motherName) {
|
||||
Alert.alert('Error', 'Please fill in all required fields');
|
||||
return;
|
||||
}
|
||||
|
||||
if (formData.maritalStatus === 'married' && !formData.spouseName) {
|
||||
Alert.alert('Error', 'Please enter your spouse name');
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
// Submit KYC
|
||||
const submission = await kycService.submitKYC(formData, null); // TODO: Add signer
|
||||
|
||||
Alert.alert(
|
||||
'KYC Submitted',
|
||||
'Your KYC application has been submitted for review. You will be notified once approved.',
|
||||
[
|
||||
{
|
||||
text: 'OK',
|
||||
onPress: () => navigation.goBack(),
|
||||
},
|
||||
]
|
||||
);
|
||||
} catch (error) {
|
||||
Alert.alert('Error', 'Failed to submit KYC. Please try again.');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const renderChildInputs = () => {
|
||||
if (!formData.numberOfChildren || formData.numberOfChildren === 0) return null;
|
||||
|
||||
return Array.from({ length: formData.numberOfChildren }, (_, index) => (
|
||||
<View key={index} style={styles.inputContainer}>
|
||||
<Text style={styles.label}>{index + 1}. Child's Name</Text>
|
||||
<View style={styles.inputWrapper}>
|
||||
<Ionicons name="person-outline" size={20} color={Colors.textGray} />
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder={`${index + 1}. child's name`}
|
||||
placeholderTextColor={Colors.textLight}
|
||||
value={formData.children?.[index]?.name || ''}
|
||||
onChangeText={(text) => updateChild(index, text)}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
));
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<View style={styles.header}>
|
||||
<TouchableOpacity onPress={() => navigation.goBack()} style={styles.backButton}>
|
||||
<Ionicons name="arrow-back" size={24} color={Colors.textDark} />
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.headerTitle}>Identity KYC</Text>
|
||||
<View style={{ width: 24 }} />
|
||||
</View>
|
||||
|
||||
<ScrollView style={styles.scrollView} showsVerticalScrollIndicator={false}>
|
||||
<View style={styles.infoCard}>
|
||||
<Ionicons name="information-circle" size={24} color={Colors.teal} />
|
||||
<Text style={styles.infoText}>
|
||||
Complete this form to become a verified Kurdistan Digital Citizen and access Governance features.
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* Personal Information */}
|
||||
<Text style={styles.sectionTitle}>Personal Information</Text>
|
||||
|
||||
<View style={styles.inputContainer}>
|
||||
<Text style={styles.label}>Full Name *</Text>
|
||||
<View style={styles.inputWrapper}>
|
||||
<Ionicons name="person-outline" size={20} color={Colors.textGray} />
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Your full name"
|
||||
placeholderTextColor={Colors.textLight}
|
||||
value={formData.fullName}
|
||||
onChangeText={(text) => updateField('fullName', text)}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.inputContainer}>
|
||||
<Text style={styles.label}>Father's Name *</Text>
|
||||
<View style={styles.inputWrapper}>
|
||||
<Ionicons name="man-outline" size={20} color={Colors.textGray} />
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Your father's name"
|
||||
placeholderTextColor={Colors.textLight}
|
||||
value={formData.fatherName}
|
||||
onChangeText={(text) => updateField('fatherName', text)}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.inputContainer}>
|
||||
<Text style={styles.label}>Grandfather's Name</Text>
|
||||
<View style={styles.inputWrapper}>
|
||||
<Ionicons name="man-outline" size={20} color={Colors.textGray} />
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Your grandfather's name"
|
||||
placeholderTextColor={Colors.textLight}
|
||||
value={formData.grandfatherName}
|
||||
onChangeText={(text) => updateField('grandfatherName', text)}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.inputContainer}>
|
||||
<Text style={styles.label}>Great-Grandfather's Name</Text>
|
||||
<View style={styles.inputWrapper}>
|
||||
<Ionicons name="man-outline" size={20} color={Colors.textGray} />
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Your great-grandfather's name"
|
||||
placeholderTextColor={Colors.textLight}
|
||||
value={formData.greatGrandfatherName}
|
||||
onChangeText={(text) => updateField('greatGrandfatherName', text)}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.inputContainer}>
|
||||
<Text style={styles.label}>Mother's Name *</Text>
|
||||
<View style={styles.inputWrapper}>
|
||||
<Ionicons name="woman-outline" size={20} color={Colors.textGray} />
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Your mother's name"
|
||||
placeholderTextColor={Colors.textLight}
|
||||
value={formData.motherName}
|
||||
onChangeText={(text) => updateField('motherName', text)}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Marital Status */}
|
||||
<Text style={styles.sectionTitle}>Marital Status</Text>
|
||||
|
||||
<View style={styles.radioGroup}>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.radioButton,
|
||||
formData.maritalStatus === 'single' && styles.radioButtonActive,
|
||||
]}
|
||||
onPress={() => updateField('maritalStatus', 'single')}
|
||||
>
|
||||
<Ionicons
|
||||
name={formData.maritalStatus === 'single' ? 'radio-button-on' : 'radio-button-off'}
|
||||
size={24}
|
||||
color={formData.maritalStatus === 'single' ? Colors.teal : Colors.textGray}
|
||||
/>
|
||||
<Text style={styles.radioLabel}>Single</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.radioButton,
|
||||
formData.maritalStatus === 'married' && styles.radioButtonActive,
|
||||
]}
|
||||
onPress={() => updateField('maritalStatus', 'married')}
|
||||
>
|
||||
<Ionicons
|
||||
name={formData.maritalStatus === 'married' ? 'radio-button-on' : 'radio-button-off'}
|
||||
size={24}
|
||||
color={formData.maritalStatus === 'married' ? Colors.teal : Colors.textGray}
|
||||
/>
|
||||
<Text style={styles.radioLabel}>Married</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{formData.maritalStatus === 'married' && (
|
||||
<>
|
||||
<View style={styles.inputContainer}>
|
||||
<Text style={styles.label}>Spouse's Name *</Text>
|
||||
<View style={styles.inputWrapper}>
|
||||
<Ionicons name="heart-outline" size={20} color={Colors.textGray} />
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Your spouse's name"
|
||||
placeholderTextColor={Colors.textLight}
|
||||
value={formData.spouseName}
|
||||
onChangeText={(text) => updateField('spouseName', text)}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.inputContainer}>
|
||||
<Text style={styles.label}>Number of Children</Text>
|
||||
<View style={styles.inputWrapper}>
|
||||
<Ionicons name="people-outline" size={20} color={Colors.textGray} />
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="0"
|
||||
placeholderTextColor={Colors.textLight}
|
||||
keyboardType="number-pad"
|
||||
value={formData.numberOfChildren?.toString() || ''}
|
||||
onChangeText={(text) => {
|
||||
const num = parseInt(text) || 0;
|
||||
updateField('numberOfChildren', num);
|
||||
if (num > 0) {
|
||||
updateField('children', Array(num).fill({ name: '', order: 0 }));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{renderChildInputs()}
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Region */}
|
||||
<Text style={styles.sectionTitle}>Region</Text>
|
||||
|
||||
<View style={styles.inputContainer}>
|
||||
<Text style={styles.label}>Select Your Region *</Text>
|
||||
<View style={styles.pickerWrapper}>
|
||||
<Picker
|
||||
selectedValue={formData.region}
|
||||
onValueChange={(value) => updateField('region', value)}
|
||||
style={styles.picker}
|
||||
>
|
||||
{Object.entries(REGION_LABELS).map(([key, value]) => (
|
||||
<Picker.Item key={key} label={value.en} value={key} />
|
||||
))}
|
||||
</Picker>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Submit Button */}
|
||||
<TouchableOpacity
|
||||
style={[styles.submitButton, loading && styles.submitButtonDisabled]}
|
||||
onPress={handleSubmit}
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? (
|
||||
<ActivityIndicator color="#FFFFFF" />
|
||||
) : (
|
||||
<>
|
||||
<Text style={styles.submitButtonText}>Submit KYC Application</Text>
|
||||
<Ionicons name="arrow-forward" size={20} color="#FFFFFF" />
|
||||
</>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
|
||||
<View style={{ height: 40 }} />
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.background,
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: Spacing.xl,
|
||||
paddingVertical: Spacing.lg,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#F0F0F0',
|
||||
},
|
||||
backButton: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: Colors.card,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: Typography.sizes.large,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.textDark,
|
||||
},
|
||||
scrollView: {
|
||||
flex: 1,
|
||||
paddingHorizontal: Spacing.xl,
|
||||
},
|
||||
infoCard: {
|
||||
flexDirection: 'row',
|
||||
backgroundColor: Colors.teal + '20',
|
||||
padding: Spacing.lg,
|
||||
borderRadius: BorderRadius.medium,
|
||||
marginVertical: Spacing.lg,
|
||||
gap: Spacing.md,
|
||||
},
|
||||
infoText: {
|
||||
flex: 1,
|
||||
fontSize: Typography.sizes.small,
|
||||
color: Colors.textDark,
|
||||
lineHeight: 20,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: Typography.sizes.large,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.textDark,
|
||||
marginTop: Spacing.xl,
|
||||
marginBottom: Spacing.md,
|
||||
},
|
||||
inputContainer: {
|
||||
marginBottom: Spacing.lg,
|
||||
},
|
||||
label: {
|
||||
fontSize: Typography.sizes.body,
|
||||
fontWeight: Typography.weights.medium,
|
||||
color: Colors.textDark,
|
||||
marginBottom: Spacing.sm,
|
||||
},
|
||||
inputWrapper: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: Colors.card,
|
||||
borderRadius: BorderRadius.medium,
|
||||
paddingHorizontal: Spacing.md,
|
||||
paddingVertical: Spacing.sm,
|
||||
borderWidth: 1,
|
||||
borderColor: '#E0E0E0',
|
||||
},
|
||||
input: {
|
||||
flex: 1,
|
||||
fontSize: Typography.sizes.medium,
|
||||
color: Colors.textDark,
|
||||
marginLeft: Spacing.sm,
|
||||
},
|
||||
radioGroup: {
|
||||
flexDirection: 'row',
|
||||
gap: Spacing.md,
|
||||
marginBottom: Spacing.lg,
|
||||
},
|
||||
radioButton: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: Colors.card,
|
||||
padding: Spacing.lg,
|
||||
borderRadius: BorderRadius.medium,
|
||||
borderWidth: 1,
|
||||
borderColor: '#E0E0E0',
|
||||
gap: Spacing.sm,
|
||||
},
|
||||
radioButtonActive: {
|
||||
borderColor: Colors.teal,
|
||||
backgroundColor: Colors.teal + '10',
|
||||
},
|
||||
radioLabel: {
|
||||
fontSize: Typography.sizes.medium,
|
||||
color: Colors.textDark,
|
||||
},
|
||||
pickerWrapper: {
|
||||
backgroundColor: Colors.card,
|
||||
borderRadius: BorderRadius.medium,
|
||||
borderWidth: 1,
|
||||
borderColor: '#E0E0E0',
|
||||
overflow: 'hidden',
|
||||
},
|
||||
picker: {
|
||||
height: 50,
|
||||
},
|
||||
submitButton: {
|
||||
flexDirection: 'row',
|
||||
backgroundColor: Colors.teal,
|
||||
borderRadius: BorderRadius.xxlarge,
|
||||
paddingVertical: Spacing.lg,
|
||||
paddingHorizontal: Spacing.xxxl,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginTop: Spacing.xl,
|
||||
gap: Spacing.sm,
|
||||
...Shadow.soft,
|
||||
},
|
||||
submitButtonDisabled: {
|
||||
opacity: 0.6,
|
||||
},
|
||||
submitButtonText: {
|
||||
fontSize: Typography.sizes.large,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: '#FFFFFF',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,316 +0,0 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { View, Text, StyleSheet, TouchableOpacity, SafeAreaView, ActivityIndicator } from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import Colors from '../../constants/colors';
|
||||
import { Typography, Spacing, BorderRadius, Shadow } from '../../constants/theme';
|
||||
import { kycService } from '../../services/kycService';
|
||||
import { KYCStatus } from '../../types/kyc';
|
||||
|
||||
export default function IdentityScreen({ navigation }: any) {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [kycStatus, setKycStatus] = useState<KYCStatus>({
|
||||
started: false,
|
||||
submitted: false,
|
||||
approved: false,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
loadKYCStatus();
|
||||
}, []);
|
||||
|
||||
const loadKYCStatus = async () => {
|
||||
try {
|
||||
const status = await kycService.getKYCStatus();
|
||||
setKycStatus(status);
|
||||
} catch (error) {
|
||||
console.error('Failed to load KYC status:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<ActivityIndicator size="large" color={Colors.teal} />
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
// If KYC approved, show citizen card access
|
||||
if (kycStatus.approved && kycStatus.citizen) {
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.title}>Digital Identity</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.content}>
|
||||
<View style={styles.approvedCard}>
|
||||
<Ionicons name="checkmark-circle" size={60} color={Colors.mint} />
|
||||
<Text style={styles.approvedTitle}>KYC Approved</Text>
|
||||
<Text style={styles.approvedSubtitle}>You are a verified Kurdistan Digital Citizen</Text>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.viewCardButton}
|
||||
onPress={() => navigation.navigate('CitizenCard')}
|
||||
>
|
||||
<Ionicons name="card-outline" size={24} color="#FFFFFF" />
|
||||
<Text style={styles.viewCardButtonText}>View Citizen Card</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<View style={styles.infoBox}>
|
||||
<Ionicons name="information-circle-outline" size={24} color={Colors.teal} />
|
||||
<Text style={styles.infoText}>
|
||||
Your citizen card grants you access to Governance (Welati) and other citizen-only features.
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
// If KYC submitted but not approved
|
||||
if (kycStatus.submitted && !kycStatus.approved) {
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.title}>Digital Identity</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.content}>
|
||||
<View style={styles.pendingCard}>
|
||||
<Ionicons name="time-outline" size={60} color={Colors.gold} />
|
||||
<Text style={styles.pendingTitle}>KYC Under Review</Text>
|
||||
<Text style={styles.pendingSubtitle}>
|
||||
Your application is being reviewed. You will be notified once approved.
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity style={styles.refreshButton} onPress={loadKYCStatus}>
|
||||
<Ionicons name="refresh-outline" size={20} color={Colors.teal} />
|
||||
<Text style={styles.refreshButtonText}>Check Status</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
// If KYC not started
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.title}>Digital Identity</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.content}>
|
||||
<View style={styles.welcomeCard}>
|
||||
<Ionicons name="person-add-outline" size={60} color={Colors.teal} />
|
||||
<Text style={styles.welcomeTitle}>Become a Digital Citizen</Text>
|
||||
<Text style={styles.welcomeSubtitle}>
|
||||
Complete KYC verification to access Governance (Welati) and become a verified Kurdistan Digital Citizen.
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.benefitsCard}>
|
||||
<Text style={styles.benefitsTitle}>Benefits:</Text>
|
||||
<View style={styles.benefitItem}>
|
||||
<Ionicons name="checkmark-circle" size={20} color={Colors.mint} />
|
||||
<Text style={styles.benefitText}>Vote on governance proposals</Text>
|
||||
</View>
|
||||
<View style={styles.benefitItem}>
|
||||
<Ionicons name="checkmark-circle" size={20} color={Colors.mint} />
|
||||
<Text style={styles.benefitText}>Access Parliamentary NFT elections</Text>
|
||||
</View>
|
||||
<View style={styles.benefitItem}>
|
||||
<Ionicons name="checkmark-circle" size={20} color={Colors.mint} />
|
||||
<Text style={styles.benefitText}>Digital citizenship certificate</Text>
|
||||
</View>
|
||||
<View style={styles.benefitItem}>
|
||||
<Ionicons name="checkmark-circle" size={20} color={Colors.mint} />
|
||||
<Text style={styles.benefitText}>Verified trust score</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.startButton}
|
||||
onPress={() => navigation.navigate('IdentityKYCForm')}
|
||||
>
|
||||
<Text style={styles.startButtonText}>Start KYC Verification</Text>
|
||||
<Ionicons name="arrow-forward" size={20} color="#FFFFFF" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.background,
|
||||
},
|
||||
header: {
|
||||
padding: Spacing.xl,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#F0F0F0',
|
||||
},
|
||||
title: {
|
||||
fontSize: 28,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
padding: Spacing.xl,
|
||||
},
|
||||
welcomeCard: {
|
||||
backgroundColor: Colors.card,
|
||||
padding: Spacing.xxxl,
|
||||
borderRadius: BorderRadius.xlarge,
|
||||
alignItems: 'center',
|
||||
...Shadow.soft,
|
||||
},
|
||||
welcomeTitle: {
|
||||
fontSize: 24,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
marginTop: Spacing.lg,
|
||||
textAlign: 'center',
|
||||
},
|
||||
welcomeSubtitle: {
|
||||
fontSize: 16,
|
||||
color: Colors.textGray,
|
||||
marginTop: Spacing.md,
|
||||
textAlign: 'center',
|
||||
lineHeight: 24,
|
||||
},
|
||||
benefitsCard: {
|
||||
backgroundColor: Colors.mint + '20',
|
||||
padding: Spacing.xl,
|
||||
borderRadius: BorderRadius.large,
|
||||
marginTop: Spacing.xl,
|
||||
},
|
||||
benefitsTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
color: Colors.textDark,
|
||||
marginBottom: Spacing.md,
|
||||
},
|
||||
benefitItem: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginTop: Spacing.sm,
|
||||
gap: Spacing.sm,
|
||||
},
|
||||
benefitText: {
|
||||
fontSize: 16,
|
||||
color: Colors.textDark,
|
||||
},
|
||||
startButton: {
|
||||
flexDirection: 'row',
|
||||
backgroundColor: Colors.teal,
|
||||
borderRadius: BorderRadius.xxlarge,
|
||||
paddingVertical: Spacing.lg,
|
||||
paddingHorizontal: Spacing.xxxl,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginTop: Spacing.xl,
|
||||
gap: Spacing.sm,
|
||||
...Shadow.soft,
|
||||
},
|
||||
startButtonText: {
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
color: '#FFFFFF',
|
||||
},
|
||||
approvedCard: {
|
||||
backgroundColor: Colors.mint + '20',
|
||||
padding: Spacing.xxxl,
|
||||
borderRadius: BorderRadius.xlarge,
|
||||
alignItems: 'center',
|
||||
...Shadow.soft,
|
||||
},
|
||||
approvedTitle: {
|
||||
fontSize: 24,
|
||||
fontWeight: '700',
|
||||
color: Colors.mint,
|
||||
marginTop: Spacing.lg,
|
||||
},
|
||||
approvedSubtitle: {
|
||||
fontSize: 16,
|
||||
color: Colors.textGray,
|
||||
marginTop: Spacing.sm,
|
||||
textAlign: 'center',
|
||||
},
|
||||
viewCardButton: {
|
||||
flexDirection: 'row',
|
||||
backgroundColor: Colors.teal,
|
||||
borderRadius: BorderRadius.xxlarge,
|
||||
paddingVertical: Spacing.lg,
|
||||
paddingHorizontal: Spacing.xxxl,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginTop: Spacing.xl,
|
||||
gap: Spacing.sm,
|
||||
...Shadow.soft,
|
||||
},
|
||||
viewCardButtonText: {
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
color: '#FFFFFF',
|
||||
},
|
||||
infoBox: {
|
||||
flexDirection: 'row',
|
||||
backgroundColor: Colors.teal + '20',
|
||||
padding: Spacing.lg,
|
||||
borderRadius: BorderRadius.medium,
|
||||
marginTop: Spacing.xl,
|
||||
gap: Spacing.md,
|
||||
},
|
||||
infoText: {
|
||||
flex: 1,
|
||||
fontSize: 14,
|
||||
color: Colors.textDark,
|
||||
lineHeight: 20,
|
||||
},
|
||||
pendingCard: {
|
||||
backgroundColor: Colors.gold + '20',
|
||||
padding: Spacing.xxxl,
|
||||
borderRadius: BorderRadius.xlarge,
|
||||
alignItems: 'center',
|
||||
...Shadow.soft,
|
||||
},
|
||||
pendingTitle: {
|
||||
fontSize: 24,
|
||||
fontWeight: '700',
|
||||
color: Colors.gold,
|
||||
marginTop: Spacing.lg,
|
||||
},
|
||||
pendingSubtitle: {
|
||||
fontSize: 16,
|
||||
color: Colors.textGray,
|
||||
marginTop: Spacing.sm,
|
||||
textAlign: 'center',
|
||||
lineHeight: 24,
|
||||
},
|
||||
refreshButton: {
|
||||
flexDirection: 'row',
|
||||
backgroundColor: Colors.card,
|
||||
borderRadius: BorderRadius.large,
|
||||
paddingVertical: Spacing.md,
|
||||
paddingHorizontal: Spacing.xl,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginTop: Spacing.xl,
|
||||
gap: Spacing.sm,
|
||||
borderWidth: 1,
|
||||
borderColor: Colors.teal,
|
||||
},
|
||||
refreshButtonText: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: Colors.teal,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,410 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
Switch,
|
||||
Alert,
|
||||
} from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import Colors from '../../constants/colors';
|
||||
import { Typography, Spacing, BorderRadius, Shadow } from '../../constants/theme';
|
||||
|
||||
interface MenuItem {
|
||||
id: string;
|
||||
icon: keyof typeof Ionicons.glyphMap;
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
onPress: () => void;
|
||||
showArrow?: boolean;
|
||||
showSwitch?: boolean;
|
||||
switchValue?: boolean;
|
||||
}
|
||||
|
||||
export default function ProfileScreen({ navigation }: any) {
|
||||
const [notificationsEnabled, setNotificationsEnabled] = useState(true);
|
||||
const [biometricEnabled, setBiometricEnabled] = useState(false);
|
||||
|
||||
const accountMenuItems: MenuItem[] = [
|
||||
{
|
||||
id: 'edit-profile',
|
||||
icon: 'person-outline',
|
||||
title: 'Edit Profile',
|
||||
subtitle: 'Update your personal information',
|
||||
onPress: () => Alert.alert('Edit Profile', 'Coming soon'),
|
||||
showArrow: true,
|
||||
},
|
||||
{
|
||||
id: 'identity',
|
||||
icon: 'card-outline',
|
||||
title: 'Digital Identity',
|
||||
subtitle: 'View your Kurdistan Citizen Card',
|
||||
onPress: () => navigation.navigate('Identity'),
|
||||
showArrow: true,
|
||||
},
|
||||
{
|
||||
id: 'trust-score',
|
||||
icon: 'star-outline',
|
||||
title: 'Trust Score',
|
||||
subtitle: '750 points',
|
||||
onPress: () => navigation.navigate('TrustScore'),
|
||||
showArrow: true,
|
||||
},
|
||||
];
|
||||
|
||||
const securityMenuItems: MenuItem[] = [
|
||||
{
|
||||
id: 'change-password',
|
||||
icon: 'lock-closed-outline',
|
||||
title: 'Change Password',
|
||||
onPress: () => Alert.alert('Change Password', 'Coming soon'),
|
||||
showArrow: true,
|
||||
},
|
||||
{
|
||||
id: 'biometric',
|
||||
icon: 'finger-print-outline',
|
||||
title: 'Biometric Authentication',
|
||||
onPress: () => {},
|
||||
showSwitch: true,
|
||||
switchValue: biometricEnabled,
|
||||
},
|
||||
{
|
||||
id: 'backup',
|
||||
icon: 'cloud-upload-outline',
|
||||
title: 'Backup Wallet',
|
||||
subtitle: 'Secure your recovery phrase',
|
||||
onPress: () => Alert.alert('Backup Wallet', 'This feature will help you backup your wallet securely.'),
|
||||
showArrow: true,
|
||||
},
|
||||
];
|
||||
|
||||
const preferencesMenuItems: MenuItem[] = [
|
||||
{
|
||||
id: 'notifications',
|
||||
icon: 'notifications-outline',
|
||||
title: 'Push Notifications',
|
||||
onPress: () => {},
|
||||
showSwitch: true,
|
||||
switchValue: notificationsEnabled,
|
||||
},
|
||||
{
|
||||
id: 'language',
|
||||
icon: 'language-outline',
|
||||
title: 'Language',
|
||||
subtitle: 'English',
|
||||
onPress: () => navigation.navigate('LanguageSelection'),
|
||||
showArrow: true,
|
||||
},
|
||||
{
|
||||
id: 'currency',
|
||||
icon: 'cash-outline',
|
||||
title: 'Currency',
|
||||
subtitle: 'USD',
|
||||
onPress: () => Alert.alert('Currency', 'Currency selection coming soon'),
|
||||
showArrow: true,
|
||||
},
|
||||
];
|
||||
|
||||
const supportMenuItems: MenuItem[] = [
|
||||
{
|
||||
id: 'help',
|
||||
icon: 'help-circle-outline',
|
||||
title: 'Help Center',
|
||||
onPress: () => Alert.alert('Help Center', 'Visit help.pezkuwichain.io'),
|
||||
showArrow: true,
|
||||
},
|
||||
{
|
||||
id: 'about',
|
||||
icon: 'information-circle-outline',
|
||||
title: 'About PezkuwiChain',
|
||||
subtitle: 'Version 1.0.0',
|
||||
onPress: () => Alert.alert('About', 'PezkuwiChain v1.0.0\nBuilding the future of Kurdish digital infrastructure'),
|
||||
showArrow: true,
|
||||
},
|
||||
{
|
||||
id: 'terms',
|
||||
icon: 'document-text-outline',
|
||||
title: 'Terms & Privacy',
|
||||
onPress: () => Alert.alert('Terms', 'View terms and privacy policy'),
|
||||
showArrow: true,
|
||||
},
|
||||
];
|
||||
|
||||
const handleLogout = () => {
|
||||
Alert.alert(
|
||||
'Logout',
|
||||
'Are you sure you want to logout?',
|
||||
[
|
||||
{ text: 'Cancel', style: 'cancel' },
|
||||
{
|
||||
text: 'Logout',
|
||||
style: 'destructive',
|
||||
onPress: () => navigation.navigate('LanguageSelection'),
|
||||
},
|
||||
]
|
||||
);
|
||||
};
|
||||
|
||||
const renderMenuItem = (item: MenuItem) => (
|
||||
<TouchableOpacity
|
||||
key={item.id}
|
||||
style={styles.menuItem}
|
||||
onPress={item.onPress}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<View style={styles.menuIconContainer}>
|
||||
<Ionicons name={item.icon} size={24} color={Colors.teal} />
|
||||
</View>
|
||||
|
||||
<View style={styles.menuContent}>
|
||||
<Text style={styles.menuTitle}>{item.title}</Text>
|
||||
{item.subtitle && <Text style={styles.menuSubtitle}>{item.subtitle}</Text>}
|
||||
</View>
|
||||
|
||||
{item.showArrow && (
|
||||
<Ionicons name="chevron-forward" size={20} color={Colors.textGray} />
|
||||
)}
|
||||
|
||||
{item.showSwitch && (
|
||||
<Switch
|
||||
value={item.switchValue}
|
||||
onValueChange={(value) => {
|
||||
if (item.id === 'notifications') {
|
||||
setNotificationsEnabled(value);
|
||||
} else if (item.id === 'biometric') {
|
||||
setBiometricEnabled(value);
|
||||
}
|
||||
}}
|
||||
trackColor={{ false: '#D0D0D0', true: Colors.teal }}
|
||||
thumbColor="#FFFFFF"
|
||||
/>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<ScrollView showsVerticalScrollIndicator={false}>
|
||||
{/* Profile Header */}
|
||||
<LinearGradient
|
||||
colors={Colors.gradients.header}
|
||||
style={styles.header}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
>
|
||||
<View style={styles.profileInfo}>
|
||||
<View style={styles.avatar}>
|
||||
<Ionicons name="person" size={40} color="#FFFFFF" />
|
||||
</View>
|
||||
|
||||
<View style={styles.userInfo}>
|
||||
<Text style={styles.userName}>Satoshi Qazi Muhammed</Text>
|
||||
<Text style={styles.userEmail}>satoshi@pezkuwichain.io</Text>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.editButton}
|
||||
onPress={() => Alert.alert('Edit Profile', 'Coming soon')}
|
||||
>
|
||||
<Ionicons name="create-outline" size={20} color="#FFFFFF" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Stats */}
|
||||
<View style={styles.statsContainer}>
|
||||
<View style={styles.statItem}>
|
||||
<Text style={styles.statValue}>750</Text>
|
||||
<Text style={styles.statLabel}>Trust Score</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.statDivider} />
|
||||
|
||||
<View style={styles.statItem}>
|
||||
<Text style={styles.statValue}>24</Text>
|
||||
<Text style={styles.statLabel}>Referrals</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.statDivider} />
|
||||
|
||||
<View style={styles.statItem}>
|
||||
<Text style={styles.statValue}>5</Text>
|
||||
<Text style={styles.statLabel}>Certificates</Text>
|
||||
</View>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
|
||||
{/* Account Section */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Account</Text>
|
||||
{accountMenuItems.map(renderMenuItem)}
|
||||
</View>
|
||||
|
||||
{/* Security Section */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Security</Text>
|
||||
{securityMenuItems.map(renderMenuItem)}
|
||||
</View>
|
||||
|
||||
{/* Preferences Section */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Preferences</Text>
|
||||
{preferencesMenuItems.map(renderMenuItem)}
|
||||
</View>
|
||||
|
||||
{/* Support Section */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Support</Text>
|
||||
{supportMenuItems.map(renderMenuItem)}
|
||||
</View>
|
||||
|
||||
{/* Logout Button */}
|
||||
<TouchableOpacity style={styles.logoutButton} onPress={handleLogout}>
|
||||
<Ionicons name="log-out-outline" size={24} color={Colors.coral} />
|
||||
<Text style={styles.logoutText}>Logout</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<View style={{ height: 40 }} />
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.background,
|
||||
},
|
||||
header: {
|
||||
paddingHorizontal: Spacing.xl,
|
||||
paddingTop: Spacing.xxxl,
|
||||
paddingBottom: Spacing.xl,
|
||||
borderBottomLeftRadius: BorderRadius.xxlarge,
|
||||
borderBottomRightRadius: BorderRadius.xxlarge,
|
||||
},
|
||||
profileInfo: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginBottom: Spacing.xl,
|
||||
},
|
||||
avatar: {
|
||||
width: 70,
|
||||
height: 70,
|
||||
borderRadius: 35,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.3)',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderWidth: 3,
|
||||
borderColor: '#FFFFFF',
|
||||
},
|
||||
userInfo: {
|
||||
flex: 1,
|
||||
marginLeft: Spacing.lg,
|
||||
},
|
||||
userName: {
|
||||
fontSize: Typography.sizes.xlarge,
|
||||
fontWeight: Typography.weights.bold,
|
||||
color: '#FFFFFF',
|
||||
marginBottom: 4,
|
||||
},
|
||||
userEmail: {
|
||||
fontSize: Typography.sizes.small,
|
||||
color: 'rgba(255, 255, 255, 0.9)',
|
||||
},
|
||||
editButton: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.3)',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
statsContainer: {
|
||||
flexDirection: 'row',
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.2)',
|
||||
borderRadius: BorderRadius.large,
|
||||
padding: Spacing.lg,
|
||||
},
|
||||
statItem: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
},
|
||||
statValue: {
|
||||
fontSize: 24,
|
||||
fontWeight: Typography.weights.bold,
|
||||
color: '#FFFFFF',
|
||||
marginBottom: 4,
|
||||
},
|
||||
statLabel: {
|
||||
fontSize: Typography.sizes.small,
|
||||
color: 'rgba(255, 255, 255, 0.9)',
|
||||
},
|
||||
statDivider: {
|
||||
width: 1,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.3)',
|
||||
marginHorizontal: Spacing.md,
|
||||
},
|
||||
section: {
|
||||
marginTop: Spacing.xl,
|
||||
paddingHorizontal: Spacing.xl,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: Typography.sizes.medium,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.textGray,
|
||||
marginBottom: Spacing.md,
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
menuItem: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: Colors.card,
|
||||
padding: Spacing.lg,
|
||||
borderRadius: BorderRadius.large,
|
||||
marginBottom: Spacing.sm,
|
||||
...Shadow.small,
|
||||
},
|
||||
menuIconContainer: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: Colors.teal + '20',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginRight: Spacing.md,
|
||||
},
|
||||
menuContent: {
|
||||
flex: 1,
|
||||
},
|
||||
menuTitle: {
|
||||
fontSize: Typography.sizes.medium,
|
||||
fontWeight: Typography.weights.medium,
|
||||
color: Colors.textDark,
|
||||
marginBottom: 2,
|
||||
},
|
||||
menuSubtitle: {
|
||||
fontSize: Typography.sizes.small,
|
||||
color: Colors.textGray,
|
||||
},
|
||||
logoutButton: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: Colors.coral + '20',
|
||||
marginHorizontal: Spacing.xl,
|
||||
marginTop: Spacing.xxxl,
|
||||
padding: Spacing.lg,
|
||||
borderRadius: BorderRadius.large,
|
||||
gap: Spacing.sm,
|
||||
},
|
||||
logoutText: {
|
||||
fontSize: Typography.sizes.medium,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.coral,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import React from 'react';
|
||||
import { View, Text, StyleSheet, SafeAreaView } from 'react-native';
|
||||
import Colors from '../../constants/colors';
|
||||
|
||||
export default function ProfileScreen() {
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<Text style={styles.title}>Profile</Text>
|
||||
<Text style={styles.subtitle}>Coming soon...</Text>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: { flex: 1, backgroundColor: Colors.background, justifyContent: 'center', alignItems: 'center' },
|
||||
title: { fontSize: 28, fontWeight: '700', color: Colors.textDark, marginBottom: 8 },
|
||||
subtitle: { fontSize: 16, color: Colors.textGray },
|
||||
});
|
||||
@@ -1,378 +0,0 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
ActivityIndicator,
|
||||
} from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import Colors from '../../constants/colors';
|
||||
import { Typography, Spacing, BorderRadius, Shadow } from '../../constants/theme';
|
||||
|
||||
interface TrustActivity {
|
||||
id: string;
|
||||
type: 'vote' | 'proposal' | 'stake' | 'community';
|
||||
description: string;
|
||||
points: number;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
export default function TrustScoreScreen({ navigation }: any) {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [trustScore] = useState(750);
|
||||
const [activities, setActivities] = useState<TrustActivity[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
loadTrustData();
|
||||
}, []);
|
||||
|
||||
const loadTrustData = async () => {
|
||||
// Mock data - replace with blockchain data
|
||||
setTimeout(() => {
|
||||
setActivities([
|
||||
{
|
||||
id: '1',
|
||||
type: 'vote',
|
||||
description: 'Voted on Proposal #42',
|
||||
points: 10,
|
||||
timestamp: Date.now() - 86400000,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'stake',
|
||||
description: 'Staked 10,000 HEZ',
|
||||
points: 50,
|
||||
timestamp: Date.now() - 172800000,
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
type: 'proposal',
|
||||
description: 'Created Proposal #45',
|
||||
points: 25,
|
||||
timestamp: Date.now() - 259200000,
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
type: 'community',
|
||||
description: 'Referred 3 new citizens',
|
||||
points: 30,
|
||||
timestamp: Date.now() - 345600000,
|
||||
},
|
||||
]);
|
||||
setLoading(false);
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
const getActivityIcon = (type: string) => {
|
||||
switch (type) {
|
||||
case 'vote':
|
||||
return 'checkmark-circle';
|
||||
case 'proposal':
|
||||
return 'bulb';
|
||||
case 'stake':
|
||||
return 'lock-closed';
|
||||
case 'community':
|
||||
return 'people';
|
||||
default:
|
||||
return 'star';
|
||||
}
|
||||
};
|
||||
|
||||
const getActivityColor = (type: string) => {
|
||||
switch (type) {
|
||||
case 'vote':
|
||||
return Colors.mint;
|
||||
case 'proposal':
|
||||
return Colors.peach;
|
||||
case 'stake':
|
||||
return Colors.blue;
|
||||
case 'community':
|
||||
return Colors.lavender;
|
||||
default:
|
||||
return Colors.teal;
|
||||
}
|
||||
};
|
||||
|
||||
const formatDate = (timestamp: number) => {
|
||||
const date = new Date(timestamp);
|
||||
const now = new Date();
|
||||
const diff = now.getTime() - date.getTime();
|
||||
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
|
||||
|
||||
if (days === 0) return 'Today';
|
||||
if (days === 1) return 'Yesterday';
|
||||
return `${days} days ago`;
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<View style={styles.header}>
|
||||
<TouchableOpacity onPress={() => navigation.goBack()} style={styles.backButton}>
|
||||
<Ionicons name="arrow-back" size={24} color={Colors.textDark} />
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.headerTitle}>Trust Score</Text>
|
||||
<View style={{ width: 40 }} />
|
||||
</View>
|
||||
|
||||
<ScrollView style={styles.content} showsVerticalScrollIndicator={false}>
|
||||
{/* Trust Score Card */}
|
||||
<LinearGradient
|
||||
colors={[Colors.gold, '#E8C896']}
|
||||
style={styles.scoreCard}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
>
|
||||
<Ionicons name="star" size={60} color="#FFFFFF" />
|
||||
<Text style={styles.scoreValue}>{trustScore}</Text>
|
||||
<Text style={styles.scoreLabel}>Your Trust Score</Text>
|
||||
|
||||
<View style={styles.scoreBadge}>
|
||||
<Text style={styles.badgeText}>🏆 Gold Tier</Text>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
|
||||
{/* Benefits */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Benefits</Text>
|
||||
|
||||
<View style={styles.benefitCard}>
|
||||
<Ionicons name="trending-up" size={24} color={Colors.mint} />
|
||||
<View style={styles.benefitText}>
|
||||
<Text style={styles.benefitTitle}>Higher PEZ Rewards</Text>
|
||||
<Text style={styles.benefitDescription}>
|
||||
Earn 1.5x more PEZ rewards from staking
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.benefitCard}>
|
||||
<Ionicons name="shield-checkmark" size={24} color={Colors.blue} />
|
||||
<View style={styles.benefitText}>
|
||||
<Text style={styles.benefitTitle}>Validator Priority</Text>
|
||||
<Text style={styles.benefitDescription}>
|
||||
Higher chance of being selected as validator
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.benefitCard}>
|
||||
<Ionicons name="megaphone" size={24} color={Colors.peach} />
|
||||
<View style={styles.benefitText}>
|
||||
<Text style={styles.benefitTitle}>Governance Weight</Text>
|
||||
<Text style={styles.benefitDescription}>
|
||||
Your votes carry more weight in proposals
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Recent Activities */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Recent Activities</Text>
|
||||
|
||||
{loading ? (
|
||||
<ActivityIndicator size="large" color={Colors.teal} />
|
||||
) : (
|
||||
activities.map((activity) => (
|
||||
<View key={activity.id} style={styles.activityCard}>
|
||||
<View
|
||||
style={[
|
||||
styles.activityIcon,
|
||||
{ backgroundColor: getActivityColor(activity.type) + '20' },
|
||||
]}
|
||||
>
|
||||
<Ionicons
|
||||
name={getActivityIcon(activity.type)}
|
||||
size={24}
|
||||
color={getActivityColor(activity.type)}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.activityInfo}>
|
||||
<Text style={styles.activityDescription}>{activity.description}</Text>
|
||||
<Text style={styles.activityDate}>{formatDate(activity.timestamp)}</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.activityPoints}>
|
||||
<Text style={styles.pointsValue}>+{activity.points}</Text>
|
||||
<Text style={styles.pointsLabel}>points</Text>
|
||||
</View>
|
||||
</View>
|
||||
))
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* How to Increase */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>How to Increase Trust Score</Text>
|
||||
|
||||
<View style={styles.tipCard}>
|
||||
<Text style={styles.tipText}>✓ Vote on governance proposals</Text>
|
||||
</View>
|
||||
<View style={styles.tipCard}>
|
||||
<Text style={styles.tipText}>✓ Stake HEZ tokens</Text>
|
||||
</View>
|
||||
<View style={styles.tipCard}>
|
||||
<Text style={styles.tipText}>✓ Create valuable proposals</Text>
|
||||
</View>
|
||||
<View style={styles.tipCard}>
|
||||
<Text style={styles.tipText}>✓ Refer new citizens</Text>
|
||||
</View>
|
||||
<View style={styles.tipCard}>
|
||||
<Text style={styles.tipText}>✓ Maintain long-term participation</Text>
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.background,
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: Spacing.xl,
|
||||
paddingVertical: Spacing.lg,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#F0F0F0',
|
||||
},
|
||||
backButton: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: Colors.card,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: Typography.sizes.large,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.textDark,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
padding: Spacing.xl,
|
||||
},
|
||||
scoreCard: {
|
||||
borderRadius: BorderRadius.xlarge,
|
||||
padding: Spacing.xxxl,
|
||||
alignItems: 'center',
|
||||
...Shadow.large,
|
||||
},
|
||||
scoreValue: {
|
||||
fontSize: 64,
|
||||
fontWeight: '700',
|
||||
color: '#FFFFFF',
|
||||
marginTop: Spacing.md,
|
||||
},
|
||||
scoreLabel: {
|
||||
fontSize: Typography.sizes.medium,
|
||||
color: '#FFFFFF',
|
||||
opacity: 0.9,
|
||||
},
|
||||
scoreBadge: {
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.3)',
|
||||
paddingHorizontal: Spacing.lg,
|
||||
paddingVertical: Spacing.sm,
|
||||
borderRadius: BorderRadius.xxlarge,
|
||||
marginTop: Spacing.lg,
|
||||
},
|
||||
badgeText: {
|
||||
fontSize: Typography.sizes.medium,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: '#FFFFFF',
|
||||
},
|
||||
section: {
|
||||
marginTop: Spacing.xxxl,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: Typography.sizes.large,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.textDark,
|
||||
marginBottom: Spacing.lg,
|
||||
},
|
||||
benefitCard: {
|
||||
flexDirection: 'row',
|
||||
backgroundColor: Colors.card,
|
||||
padding: Spacing.lg,
|
||||
borderRadius: BorderRadius.large,
|
||||
marginBottom: Spacing.md,
|
||||
...Shadow.small,
|
||||
},
|
||||
benefitText: {
|
||||
flex: 1,
|
||||
marginLeft: Spacing.md,
|
||||
},
|
||||
benefitTitle: {
|
||||
fontSize: Typography.sizes.medium,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.textDark,
|
||||
marginBottom: 4,
|
||||
},
|
||||
benefitDescription: {
|
||||
fontSize: Typography.sizes.small,
|
||||
color: Colors.textGray,
|
||||
},
|
||||
activityCard: {
|
||||
flexDirection: 'row',
|
||||
backgroundColor: Colors.card,
|
||||
padding: Spacing.lg,
|
||||
borderRadius: BorderRadius.large,
|
||||
marginBottom: Spacing.md,
|
||||
alignItems: 'center',
|
||||
...Shadow.small,
|
||||
},
|
||||
activityIcon: {
|
||||
width: 50,
|
||||
height: 50,
|
||||
borderRadius: 25,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
activityInfo: {
|
||||
flex: 1,
|
||||
marginLeft: Spacing.md,
|
||||
},
|
||||
activityDescription: {
|
||||
fontSize: Typography.sizes.medium,
|
||||
fontWeight: Typography.weights.medium,
|
||||
color: Colors.textDark,
|
||||
marginBottom: 4,
|
||||
},
|
||||
activityDate: {
|
||||
fontSize: Typography.sizes.small,
|
||||
color: Colors.textGray,
|
||||
},
|
||||
activityPoints: {
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
pointsValue: {
|
||||
fontSize: Typography.sizes.large,
|
||||
fontWeight: Typography.weights.semibold,
|
||||
color: Colors.mint,
|
||||
},
|
||||
pointsLabel: {
|
||||
fontSize: Typography.sizes.small,
|
||||
color: Colors.textGray,
|
||||
},
|
||||
tipCard: {
|
||||
backgroundColor: Colors.mint + '10',
|
||||
padding: Spacing.md,
|
||||
borderRadius: BorderRadius.medium,
|
||||
marginBottom: Spacing.sm,
|
||||
},
|
||||
tipText: {
|
||||
fontSize: Typography.sizes.medium,
|
||||
color: Colors.textDark,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,587 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
Share,
|
||||
Alert,
|
||||
} from 'react-native';
|
||||
import * as Clipboard from 'expo-clipboard';
|
||||
import QRCode from 'react-native-qrcode-svg';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import Colors from '../../constants/colors';
|
||||
|
||||
interface ReferralStats {
|
||||
totalReferrals: number;
|
||||
activeReferrals: number;
|
||||
totalRewards: number;
|
||||
pendingRewards: number;
|
||||
}
|
||||
|
||||
interface Referral {
|
||||
id: string;
|
||||
name: string;
|
||||
joinDate: string;
|
||||
status: 'active' | 'pending' | 'inactive';
|
||||
rewardEarned: number;
|
||||
tier: number;
|
||||
}
|
||||
|
||||
export default function ReferralScreen() {
|
||||
const [referralCode] = useState('PKW-2024-KURD-5X7Y');
|
||||
const [stats] = useState<ReferralStats>({
|
||||
totalReferrals: 12,
|
||||
activeReferrals: 8,
|
||||
totalRewards: 2450,
|
||||
pendingRewards: 350,
|
||||
});
|
||||
|
||||
const [referrals] = useState<Referral[]>([
|
||||
{
|
||||
id: '1',
|
||||
name: 'Ahmed Karwan',
|
||||
joinDate: '2024-01-15',
|
||||
status: 'active',
|
||||
rewardEarned: 500,
|
||||
tier: 1,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Layla Sherzad',
|
||||
joinDate: '2024-01-20',
|
||||
status: 'active',
|
||||
rewardEarned: 500,
|
||||
tier: 1,
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'Saman Aziz',
|
||||
joinDate: '2024-02-05',
|
||||
status: 'active',
|
||||
rewardEarned: 250,
|
||||
tier: 2,
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
name: 'Hana Dilshad',
|
||||
joinDate: '2024-02-18',
|
||||
status: 'pending',
|
||||
rewardEarned: 0,
|
||||
tier: 1,
|
||||
},
|
||||
]);
|
||||
|
||||
const copyToClipboard = async () => {
|
||||
await Clipboard.setStringAsync(referralCode);
|
||||
Alert.alert('✓ Copied!', 'Referral code copied to clipboard');
|
||||
};
|
||||
|
||||
const shareReferralCode = async () => {
|
||||
try {
|
||||
await Share.share({
|
||||
message: `Join PezkuwiChain - Digital Kurdistan's Blockchain Platform!\n\nUse my referral code: ${referralCode}\n\nEarn rewards and be part of building Digital Kurdistan! 🦅`,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error sharing:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusColor = (status: string) => {
|
||||
switch (status) {
|
||||
case 'active':
|
||||
return Colors.success;
|
||||
case 'pending':
|
||||
return Colors.warning;
|
||||
case 'inactive':
|
||||
return Colors.textGray;
|
||||
default:
|
||||
return Colors.textGray;
|
||||
}
|
||||
};
|
||||
|
||||
const getTierReward = (tier: number) => {
|
||||
switch (tier) {
|
||||
case 1:
|
||||
return '500 PEZ';
|
||||
case 2:
|
||||
return '250 PEZ';
|
||||
case 3:
|
||||
return '100 PEZ';
|
||||
default:
|
||||
return '50 PEZ';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<ScrollView showsVerticalScrollIndicator={false}>
|
||||
{/* Header */}
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.headerTitle}>Referral Program</Text>
|
||||
<Text style={styles.headerSubtitle}>
|
||||
Invite friends and earn rewards together
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* Referral Code Card */}
|
||||
<View style={styles.codeCard}>
|
||||
<Text style={styles.codeLabel}>Your Referral Code</Text>
|
||||
<View style={styles.qrContainer}>
|
||||
<QRCode value={referralCode} size={120} />
|
||||
</View>
|
||||
<View style={styles.codeBox}>
|
||||
<Text style={styles.codeText}>{referralCode}</Text>
|
||||
</View>
|
||||
<View style={styles.actionButtons}>
|
||||
<TouchableOpacity
|
||||
style={styles.actionButton}
|
||||
onPress={copyToClipboard}
|
||||
>
|
||||
<Ionicons name="copy-outline" size={20} color={Colors.primary} />
|
||||
<Text style={styles.actionButtonText}>Copy Code</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[styles.actionButton, styles.shareButton]}
|
||||
onPress={shareReferralCode}
|
||||
>
|
||||
<Ionicons name="share-social-outline" size={20} color="white" />
|
||||
<Text style={styles.shareButtonText}>Share</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Statistics Grid */}
|
||||
<View style={styles.statsGrid}>
|
||||
<View style={styles.statCard}>
|
||||
<Ionicons name="people-outline" size={28} color={Colors.primary} />
|
||||
<Text style={styles.statValue}>{stats.totalReferrals}</Text>
|
||||
<Text style={styles.statLabel}>Total Referrals</Text>
|
||||
</View>
|
||||
<View style={styles.statCard}>
|
||||
<Ionicons
|
||||
name="checkmark-circle-outline"
|
||||
size={28}
|
||||
color={Colors.success}
|
||||
/>
|
||||
<Text style={styles.statValue}>{stats.activeReferrals}</Text>
|
||||
<Text style={styles.statLabel}>Active</Text>
|
||||
</View>
|
||||
<View style={styles.statCard}>
|
||||
<Ionicons name="trophy-outline" size={28} color={Colors.kurdishGold} />
|
||||
<Text style={styles.statValue}>{stats.totalRewards}</Text>
|
||||
<Text style={styles.statLabel}>Total Rewards (PEZ)</Text>
|
||||
</View>
|
||||
<View style={styles.statCard}>
|
||||
<Ionicons name="time-outline" size={28} color={Colors.warning} />
|
||||
<Text style={styles.statValue}>{stats.pendingRewards}</Text>
|
||||
<Text style={styles.statLabel}>Pending (PEZ)</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Reward Tiers */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Reward Tiers</Text>
|
||||
<View style={styles.tierCard}>
|
||||
<View style={styles.tierRow}>
|
||||
<View style={styles.tierBadge}>
|
||||
<Text style={styles.tierBadgeText}>Tier 1</Text>
|
||||
</View>
|
||||
<Text style={styles.tierDescription}>Direct Referrals</Text>
|
||||
<Text style={styles.tierReward}>500 PEZ</Text>
|
||||
</View>
|
||||
<View style={styles.tierRow}>
|
||||
<View style={[styles.tierBadge, { backgroundColor: Colors.success }]}>
|
||||
<Text style={styles.tierBadgeText}>Tier 2</Text>
|
||||
</View>
|
||||
<Text style={styles.tierDescription}>2nd Level Referrals</Text>
|
||||
<Text style={styles.tierReward}>250 PEZ</Text>
|
||||
</View>
|
||||
<View style={styles.tierRow}>
|
||||
<View style={[styles.tierBadge, { backgroundColor: Colors.kurdishGold }]}>
|
||||
<Text style={styles.tierBadgeText}>Tier 3</Text>
|
||||
</View>
|
||||
<Text style={styles.tierDescription}>3rd Level Referrals</Text>
|
||||
<Text style={styles.tierReward}>100 PEZ</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Referral List */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Your Referrals</Text>
|
||||
{referrals.map((referral) => (
|
||||
<View key={referral.id} style={styles.referralCard}>
|
||||
<View style={styles.referralHeader}>
|
||||
<View style={styles.avatarCircle}>
|
||||
<Text style={styles.avatarText}>
|
||||
{referral.name.charAt(0)}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.referralInfo}>
|
||||
<Text style={styles.referralName}>{referral.name}</Text>
|
||||
<Text style={styles.referralDate}>
|
||||
Joined: {referral.joinDate}
|
||||
</Text>
|
||||
</View>
|
||||
<View
|
||||
style={[
|
||||
styles.statusBadge,
|
||||
{ backgroundColor: getStatusColor(referral.status) + '20' },
|
||||
]}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
styles.statusText,
|
||||
{ color: getStatusColor(referral.status) },
|
||||
]}
|
||||
>
|
||||
{referral.status.charAt(0).toUpperCase() +
|
||||
referral.status.slice(1)}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.referralFooter}>
|
||||
<View style={styles.tierInfo}>
|
||||
<Ionicons
|
||||
name="ribbon-outline"
|
||||
size={16}
|
||||
color={Colors.primary}
|
||||
/>
|
||||
<Text style={styles.tierText}>Tier {referral.tier}</Text>
|
||||
</View>
|
||||
<Text style={styles.rewardText}>
|
||||
Earned: {referral.rewardEarned} PEZ
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
|
||||
{/* How It Works */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>How It Works</Text>
|
||||
<View style={styles.infoCard}>
|
||||
<View style={styles.infoRow}>
|
||||
<View style={styles.stepNumber}>
|
||||
<Text style={styles.stepNumberText}>1</Text>
|
||||
</View>
|
||||
<Text style={styles.infoText}>
|
||||
Share your unique referral code with friends
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.infoRow}>
|
||||
<View style={styles.stepNumber}>
|
||||
<Text style={styles.stepNumberText}>2</Text>
|
||||
</View>
|
||||
<Text style={styles.infoText}>
|
||||
They sign up and complete KYC verification
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.infoRow}>
|
||||
<View style={styles.stepNumber}>
|
||||
<Text style={styles.stepNumberText}>3</Text>
|
||||
</View>
|
||||
<Text style={styles.infoText}>
|
||||
Both of you earn PEZ rewards based on tier level
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.infoRow}>
|
||||
<View style={styles.stepNumber}>
|
||||
<Text style={styles.stepNumberText}>4</Text>
|
||||
</View>
|
||||
<Text style={styles.infoText}>
|
||||
Rewards are distributed automatically to your wallet
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={{ height: 40 }} />
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: Colors.background,
|
||||
},
|
||||
header: {
|
||||
paddingHorizontal: 20,
|
||||
paddingTop: 20,
|
||||
paddingBottom: 16,
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: 28,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
marginBottom: 4,
|
||||
},
|
||||
headerSubtitle: {
|
||||
fontSize: 15,
|
||||
color: Colors.textGray,
|
||||
},
|
||||
codeCard: {
|
||||
backgroundColor: 'white',
|
||||
marginHorizontal: 20,
|
||||
marginBottom: 20,
|
||||
borderRadius: 16,
|
||||
padding: 24,
|
||||
alignItems: 'center',
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.05,
|
||||
shadowRadius: 8,
|
||||
elevation: 2,
|
||||
},
|
||||
codeLabel: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: Colors.textDark,
|
||||
marginBottom: 20,
|
||||
},
|
||||
qrContainer: {
|
||||
padding: 16,
|
||||
backgroundColor: Colors.background,
|
||||
borderRadius: 12,
|
||||
marginBottom: 20,
|
||||
},
|
||||
codeBox: {
|
||||
backgroundColor: Colors.background,
|
||||
paddingHorizontal: 20,
|
||||
paddingVertical: 12,
|
||||
borderRadius: 10,
|
||||
marginBottom: 20,
|
||||
},
|
||||
codeText: {
|
||||
fontSize: 18,
|
||||
fontWeight: '700',
|
||||
color: Colors.primary,
|
||||
letterSpacing: 1,
|
||||
},
|
||||
actionButtons: {
|
||||
flexDirection: 'row',
|
||||
gap: 12,
|
||||
width: '100%',
|
||||
},
|
||||
actionButton: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingVertical: 12,
|
||||
borderRadius: 10,
|
||||
backgroundColor: Colors.background,
|
||||
gap: 6,
|
||||
},
|
||||
actionButtonText: {
|
||||
fontSize: 15,
|
||||
fontWeight: '600',
|
||||
color: Colors.primary,
|
||||
},
|
||||
shareButton: {
|
||||
backgroundColor: Colors.primary,
|
||||
},
|
||||
shareButtonText: {
|
||||
fontSize: 15,
|
||||
fontWeight: '600',
|
||||
color: 'white',
|
||||
},
|
||||
statsGrid: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
paddingHorizontal: 20,
|
||||
gap: 12,
|
||||
marginBottom: 24,
|
||||
},
|
||||
statCard: {
|
||||
flex: 1,
|
||||
minWidth: '47%',
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 14,
|
||||
padding: 16,
|
||||
alignItems: 'center',
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.04,
|
||||
shadowRadius: 6,
|
||||
elevation: 1,
|
||||
},
|
||||
statValue: {
|
||||
fontSize: 24,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
marginTop: 8,
|
||||
marginBottom: 4,
|
||||
},
|
||||
statLabel: {
|
||||
fontSize: 13,
|
||||
color: Colors.textGray,
|
||||
textAlign: 'center',
|
||||
},
|
||||
section: {
|
||||
paddingHorizontal: 20,
|
||||
marginBottom: 24,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 20,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
marginBottom: 12,
|
||||
},
|
||||
tierCard: {
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 14,
|
||||
padding: 16,
|
||||
gap: 12,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.04,
|
||||
shadowRadius: 6,
|
||||
elevation: 1,
|
||||
},
|
||||
tierRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 12,
|
||||
},
|
||||
tierBadge: {
|
||||
backgroundColor: Colors.primary,
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 6,
|
||||
borderRadius: 8,
|
||||
minWidth: 70,
|
||||
alignItems: 'center',
|
||||
},
|
||||
tierBadgeText: {
|
||||
fontSize: 13,
|
||||
fontWeight: '700',
|
||||
color: 'white',
|
||||
},
|
||||
tierDescription: {
|
||||
flex: 1,
|
||||
fontSize: 14,
|
||||
color: Colors.textDark,
|
||||
},
|
||||
tierReward: {
|
||||
fontSize: 15,
|
||||
fontWeight: '700',
|
||||
color: Colors.kurdishGold,
|
||||
},
|
||||
referralCard: {
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 14,
|
||||
padding: 16,
|
||||
marginBottom: 12,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.04,
|
||||
shadowRadius: 6,
|
||||
elevation: 1,
|
||||
},
|
||||
referralHeader: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginBottom: 12,
|
||||
},
|
||||
avatarCircle: {
|
||||
width: 44,
|
||||
height: 44,
|
||||
borderRadius: 22,
|
||||
backgroundColor: Colors.primary + '20',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginRight: 12,
|
||||
},
|
||||
avatarText: {
|
||||
fontSize: 18,
|
||||
fontWeight: '700',
|
||||
color: Colors.primary,
|
||||
},
|
||||
referralInfo: {
|
||||
flex: 1,
|
||||
},
|
||||
referralName: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: Colors.textDark,
|
||||
marginBottom: 2,
|
||||
},
|
||||
referralDate: {
|
||||
fontSize: 13,
|
||||
color: Colors.textGray,
|
||||
},
|
||||
statusBadge: {
|
||||
paddingHorizontal: 10,
|
||||
paddingVertical: 4,
|
||||
borderRadius: 8,
|
||||
},
|
||||
statusText: {
|
||||
fontSize: 12,
|
||||
fontWeight: '600',
|
||||
},
|
||||
referralFooter: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingTop: 12,
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: Colors.background,
|
||||
},
|
||||
tierInfo: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
},
|
||||
tierText: {
|
||||
fontSize: 14,
|
||||
color: Colors.textDark,
|
||||
fontWeight: '500',
|
||||
},
|
||||
rewardText: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: Colors.success,
|
||||
},
|
||||
infoCard: {
|
||||
backgroundColor: 'white',
|
||||
borderRadius: 14,
|
||||
padding: 20,
|
||||
gap: 16,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.04,
|
||||
shadowRadius: 6,
|
||||
elevation: 1,
|
||||
},
|
||||
infoRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-start',
|
||||
gap: 12,
|
||||
},
|
||||
stepNumber: {
|
||||
width: 28,
|
||||
height: 28,
|
||||
borderRadius: 14,
|
||||
backgroundColor: Colors.primary,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
stepNumberText: {
|
||||
fontSize: 14,
|
||||
fontWeight: '700',
|
||||
color: 'white',
|
||||
},
|
||||
infoText: {
|
||||
flex: 1,
|
||||
fontSize: 14,
|
||||
color: Colors.textDark,
|
||||
lineHeight: 20,
|
||||
paddingTop: 4,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,398 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
SafeAreaView,
|
||||
TextInput,
|
||||
ScrollView,
|
||||
Alert,
|
||||
ActivityIndicator,
|
||||
Clipboard,
|
||||
} from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { usePolkadot } from '../../contexts/PolkadotContext';
|
||||
|
||||
export default function CreateWalletScreen({ navigation }: any) {
|
||||
const { createWallet, isLoading } = usePolkadot();
|
||||
|
||||
const [walletName, setWalletName] = useState('My Wallet');
|
||||
const [password, setPassword] = useState('');
|
||||
const [confirmPassword, setConfirmPassword] = useState('');
|
||||
const [step, setStep] = useState<'form' | 'seed'>('form');
|
||||
const [seedPhrase, setSeedPhrase] = useState('');
|
||||
const [seedConfirmed, setSeedConfirmed] = useState(false);
|
||||
|
||||
const handleCreateWallet = async () => {
|
||||
// Validations
|
||||
if (!walletName.trim()) {
|
||||
Alert.alert('Error', 'Please enter a wallet name');
|
||||
return;
|
||||
}
|
||||
|
||||
if (password.length < 6) {
|
||||
Alert.alert('Error', 'Password must be at least 6 characters');
|
||||
return;
|
||||
}
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
Alert.alert('Error', 'Passwords do not match');
|
||||
return;
|
||||
}
|
||||
|
||||
// Create wallet
|
||||
const result = await createWallet(walletName, password);
|
||||
|
||||
if (result.success && result.mnemonic) {
|
||||
setSeedPhrase(result.mnemonic);
|
||||
setStep('seed');
|
||||
} else {
|
||||
Alert.alert('Error', result.error || 'Failed to create wallet');
|
||||
}
|
||||
};
|
||||
|
||||
const handleCopySeed = () => {
|
||||
Clipboard.setString(seedPhrase);
|
||||
Alert.alert('Copied!', 'Seed phrase copied to clipboard');
|
||||
};
|
||||
|
||||
const handleComplete = () => {
|
||||
if (!seedConfirmed) {
|
||||
Alert.alert(
|
||||
'Important!',
|
||||
'Please confirm that you have backed up your seed phrase. You will need it to recover your wallet.',
|
||||
[
|
||||
{ text: 'Cancel', style: 'cancel' },
|
||||
{
|
||||
text: 'I Have Backed It Up',
|
||||
onPress: () => {
|
||||
setSeedConfirmed(true);
|
||||
navigation.navigate('MainTabs');
|
||||
},
|
||||
},
|
||||
]
|
||||
);
|
||||
} else {
|
||||
navigation.navigate('MainTabs');
|
||||
}
|
||||
};
|
||||
|
||||
if (step === 'seed') {
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<LinearGradient
|
||||
colors={['#F08080', '#E8C896']}
|
||||
style={styles.gradient}
|
||||
>
|
||||
<ScrollView contentContainerStyle={styles.scrollContent}>
|
||||
<View style={styles.header}>
|
||||
<Ionicons name="key" size={60} color="#FFF" />
|
||||
<Text style={styles.title}>Your Seed Phrase</Text>
|
||||
<Text style={styles.subtitle}>
|
||||
Write down these 12 words in order. Keep them safe and secret.
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.card}>
|
||||
<View style={styles.warningBanner}>
|
||||
<Ionicons name="warning" size={24} color="#FF6B6B" />
|
||||
<Text style={styles.warningText}>
|
||||
Never share your seed phrase with anyone!
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.seedContainer}>
|
||||
{seedPhrase.split(' ').map((word, index) => (
|
||||
<View key={index} style={styles.seedWord}>
|
||||
<Text style={styles.seedNumber}>{index + 1}.</Text>
|
||||
<Text style={styles.seedText}>{word}</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.copyButton}
|
||||
onPress={handleCopySeed}
|
||||
>
|
||||
<Ionicons name="copy" size={20} color="#FFF" />
|
||||
<Text style={styles.copyButtonText}>Copy to Clipboard</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<View style={styles.checkboxContainer}>
|
||||
<TouchableOpacity
|
||||
style={styles.checkbox}
|
||||
onPress={() => setSeedConfirmed(!seedConfirmed)}
|
||||
>
|
||||
{seedConfirmed && (
|
||||
<Ionicons name="checkmark" size={20} color="#FFF" />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.checkboxLabel}>
|
||||
I have written down my seed phrase in a safe place
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.continueButton,
|
||||
!seedConfirmed && styles.continueButtonDisabled,
|
||||
]}
|
||||
onPress={handleComplete}
|
||||
disabled={!seedConfirmed}
|
||||
>
|
||||
<Text style={styles.continueButtonText}>Continue</Text>
|
||||
<Ionicons name="arrow-forward" size={20} color="#FFF" />
|
||||
</TouchableOpacity>
|
||||
</ScrollView>
|
||||
</LinearGradient>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<LinearGradient colors={['#F08080', '#E8C896']} style={styles.gradient}>
|
||||
<ScrollView contentContainerStyle={styles.scrollContent}>
|
||||
<TouchableOpacity
|
||||
style={styles.backButton}
|
||||
onPress={() => navigation.goBack()}
|
||||
>
|
||||
<Ionicons name="arrow-back" size={24} color="#FFF" />
|
||||
</TouchableOpacity>
|
||||
|
||||
<View style={styles.header}>
|
||||
<Ionicons name="add-circle" size={60} color="#FFF" />
|
||||
<Text style={styles.title}>Create New Wallet</Text>
|
||||
<Text style={styles.subtitle}>
|
||||
Set up your new PezkuwiChain wallet
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.card}>
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.label}>Wallet Name</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Enter wallet name"
|
||||
value={walletName}
|
||||
onChangeText={setWalletName}
|
||||
placeholderTextColor="#999"
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.label}>Password</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="At least 6 characters"
|
||||
value={password}
|
||||
onChangeText={setPassword}
|
||||
secureTextEntry
|
||||
placeholderTextColor="#999"
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.label}>Confirm Password</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Re-enter password"
|
||||
value={confirmPassword}
|
||||
onChangeText={setConfirmPassword}
|
||||
secureTextEntry
|
||||
placeholderTextColor="#999"
|
||||
/>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.createButton}
|
||||
onPress={handleCreateWallet}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? (
|
||||
<ActivityIndicator color="#FFF" />
|
||||
) : (
|
||||
<>
|
||||
<Text style={styles.createButtonText}>Create Wallet</Text>
|
||||
<Ionicons name="arrow-forward" size={20} color="#FFF" />
|
||||
</>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</LinearGradient>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
gradient: {
|
||||
flex: 1,
|
||||
},
|
||||
scrollContent: {
|
||||
padding: 20,
|
||||
},
|
||||
backButton: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: 'rgba(255,255,255,0.3)',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginBottom: 20,
|
||||
},
|
||||
header: {
|
||||
alignItems: 'center',
|
||||
marginBottom: 30,
|
||||
},
|
||||
title: {
|
||||
fontSize: 28,
|
||||
fontWeight: 'bold',
|
||||
color: '#FFF',
|
||||
marginTop: 16,
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 16,
|
||||
color: '#FFF',
|
||||
marginTop: 8,
|
||||
textAlign: 'center',
|
||||
opacity: 0.9,
|
||||
},
|
||||
card: {
|
||||
backgroundColor: '#FFF',
|
||||
borderRadius: 20,
|
||||
padding: 24,
|
||||
},
|
||||
inputGroup: {
|
||||
marginBottom: 20,
|
||||
},
|
||||
label: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: '#333',
|
||||
marginBottom: 8,
|
||||
},
|
||||
input: {
|
||||
backgroundColor: '#F5F5F5',
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
fontSize: 16,
|
||||
color: '#333',
|
||||
},
|
||||
createButton: {
|
||||
backgroundColor: '#F08080',
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: 8,
|
||||
marginTop: 10,
|
||||
},
|
||||
createButtonText: {
|
||||
color: '#FFF',
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
},
|
||||
warningBanner: {
|
||||
backgroundColor: '#FFF5F5',
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 12,
|
||||
marginBottom: 20,
|
||||
borderWidth: 1,
|
||||
borderColor: '#FFE0E0',
|
||||
},
|
||||
warningText: {
|
||||
flex: 1,
|
||||
fontSize: 14,
|
||||
color: '#FF6B6B',
|
||||
fontWeight: '600',
|
||||
},
|
||||
seedContainer: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
gap: 12,
|
||||
marginBottom: 20,
|
||||
},
|
||||
seedWord: {
|
||||
width: '30%',
|
||||
backgroundColor: '#F5F5F5',
|
||||
borderRadius: 8,
|
||||
padding: 12,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
},
|
||||
seedNumber: {
|
||||
fontSize: 12,
|
||||
color: '#999',
|
||||
fontWeight: '600',
|
||||
},
|
||||
seedText: {
|
||||
fontSize: 14,
|
||||
color: '#333',
|
||||
fontWeight: '600',
|
||||
},
|
||||
copyButton: {
|
||||
backgroundColor: '#7DD3C0',
|
||||
borderRadius: 12,
|
||||
padding: 14,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: 8,
|
||||
},
|
||||
copyButtonText: {
|
||||
color: '#FFF',
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
},
|
||||
checkboxContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 12,
|
||||
marginTop: 20,
|
||||
},
|
||||
checkbox: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
borderRadius: 6,
|
||||
borderWidth: 2,
|
||||
borderColor: '#FFF',
|
||||
backgroundColor: 'rgba(255,255,255,0.2)',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
checkboxLabel: {
|
||||
flex: 1,
|
||||
fontSize: 14,
|
||||
color: '#FFF',
|
||||
},
|
||||
continueButton: {
|
||||
backgroundColor: '#FFF',
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: 8,
|
||||
marginTop: 20,
|
||||
},
|
||||
continueButtonDisabled: {
|
||||
opacity: 0.5,
|
||||
},
|
||||
continueButtonText: {
|
||||
color: '#F08080',
|
||||
fontSize: 18,
|
||||
fontWeight: '700',
|
||||
},
|
||||
});
|
||||
@@ -1,267 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
SafeAreaView,
|
||||
TextInput,
|
||||
ScrollView,
|
||||
Alert,
|
||||
ActivityIndicator,
|
||||
} from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { usePolkadot } from '../../contexts/PolkadotContext';
|
||||
|
||||
export default function ImportWalletScreen({ navigation }: any) {
|
||||
const { importWallet, isLoading } = usePolkadot();
|
||||
|
||||
const [walletName, setWalletName] = useState('Imported Wallet');
|
||||
const [seedPhrase, setSeedPhrase] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [confirmPassword, setConfirmPassword] = useState('');
|
||||
|
||||
const handleImportWallet = async () => {
|
||||
// Validations
|
||||
if (!walletName.trim()) {
|
||||
Alert.alert('Error', 'Please enter a wallet name');
|
||||
return;
|
||||
}
|
||||
|
||||
const trimmedSeed = seedPhrase.trim();
|
||||
const wordCount = trimmedSeed.split(/\s+/).length;
|
||||
|
||||
if (wordCount !== 12 && wordCount !== 24) {
|
||||
Alert.alert('Error', 'Seed phrase must be 12 or 24 words');
|
||||
return;
|
||||
}
|
||||
|
||||
if (password.length < 6) {
|
||||
Alert.alert('Error', 'Password must be at least 6 characters');
|
||||
return;
|
||||
}
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
Alert.alert('Error', 'Passwords do not match');
|
||||
return;
|
||||
}
|
||||
|
||||
// Import wallet
|
||||
const result = await importWallet(trimmedSeed, walletName, password);
|
||||
|
||||
if (result.success) {
|
||||
Alert.alert(
|
||||
'Success!',
|
||||
'Wallet imported successfully',
|
||||
[
|
||||
{
|
||||
text: 'OK',
|
||||
onPress: () => navigation.navigate('MainTabs'),
|
||||
},
|
||||
]
|
||||
);
|
||||
} else {
|
||||
Alert.alert('Error', result.error || 'Failed to import wallet');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<LinearGradient colors={['#7DD3C0', '#98D8C8']} style={styles.gradient}>
|
||||
<ScrollView contentContainerStyle={styles.scrollContent}>
|
||||
<TouchableOpacity
|
||||
style={styles.backButton}
|
||||
onPress={() => navigation.goBack()}
|
||||
>
|
||||
<Ionicons name="arrow-back" size={24} color="#FFF" />
|
||||
</TouchableOpacity>
|
||||
|
||||
<View style={styles.header}>
|
||||
<Ionicons name="download" size={60} color="#FFF" />
|
||||
<Text style={styles.title}>Import Wallet</Text>
|
||||
<Text style={styles.subtitle}>
|
||||
Restore your wallet using your seed phrase
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.card}>
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.label}>Wallet Name</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Enter wallet name"
|
||||
value={walletName}
|
||||
onChangeText={setWalletName}
|
||||
placeholderTextColor="#999"
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.label}>Seed Phrase (12 or 24 words)</Text>
|
||||
<TextInput
|
||||
style={[styles.input, styles.seedInput]}
|
||||
placeholder="Enter your seed phrase separated by spaces"
|
||||
value={seedPhrase}
|
||||
onChangeText={setSeedPhrase}
|
||||
multiline
|
||||
numberOfLines={4}
|
||||
placeholderTextColor="#999"
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
/>
|
||||
<Text style={styles.hint}>
|
||||
Separate each word with a space
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.label}>Password</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="At least 6 characters"
|
||||
value={password}
|
||||
onChangeText={setPassword}
|
||||
secureTextEntry
|
||||
placeholderTextColor="#999"
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.label}>Confirm Password</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Re-enter password"
|
||||
value={confirmPassword}
|
||||
onChangeText={setConfirmPassword}
|
||||
secureTextEntry
|
||||
placeholderTextColor="#999"
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.warningBox}>
|
||||
<Ionicons name="information-circle" size={24} color="#7DD3C0" />
|
||||
<Text style={styles.warningText}>
|
||||
Make sure you're in a safe place. Never share your seed phrase with anyone.
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.importButton}
|
||||
onPress={handleImportWallet}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? (
|
||||
<ActivityIndicator color="#FFF" />
|
||||
) : (
|
||||
<>
|
||||
<Text style={styles.importButtonText}>Import Wallet</Text>
|
||||
<Ionicons name="arrow-forward" size={20} color="#FFF" />
|
||||
</>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</LinearGradient>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
gradient: {
|
||||
flex: 1,
|
||||
},
|
||||
scrollContent: {
|
||||
padding: 20,
|
||||
},
|
||||
backButton: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: 'rgba(255,255,255,0.3)',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginBottom: 20,
|
||||
},
|
||||
header: {
|
||||
alignItems: 'center',
|
||||
marginBottom: 30,
|
||||
},
|
||||
title: {
|
||||
fontSize: 28,
|
||||
fontWeight: 'bold',
|
||||
color: '#FFF',
|
||||
marginTop: 16,
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 16,
|
||||
color: '#FFF',
|
||||
marginTop: 8,
|
||||
textAlign: 'center',
|
||||
opacity: 0.9,
|
||||
},
|
||||
card: {
|
||||
backgroundColor: '#FFF',
|
||||
borderRadius: 20,
|
||||
padding: 24,
|
||||
},
|
||||
inputGroup: {
|
||||
marginBottom: 20,
|
||||
},
|
||||
label: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: '#333',
|
||||
marginBottom: 8,
|
||||
},
|
||||
input: {
|
||||
backgroundColor: '#F5F5F5',
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
fontSize: 16,
|
||||
color: '#333',
|
||||
},
|
||||
seedInput: {
|
||||
minHeight: 100,
|
||||
textAlignVertical: 'top',
|
||||
},
|
||||
hint: {
|
||||
fontSize: 12,
|
||||
color: '#999',
|
||||
marginTop: 6,
|
||||
},
|
||||
warningBox: {
|
||||
backgroundColor: '#F0F9F7',
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 12,
|
||||
marginBottom: 20,
|
||||
borderWidth: 1,
|
||||
borderColor: '#D0F0E8',
|
||||
},
|
||||
warningText: {
|
||||
flex: 1,
|
||||
fontSize: 14,
|
||||
color: '#5DBEA3',
|
||||
lineHeight: 20,
|
||||
},
|
||||
importButton: {
|
||||
backgroundColor: '#7DD3C0',
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: 8,
|
||||
},
|
||||
importButtonText: {
|
||||
color: '#FFF',
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
},
|
||||
});
|
||||
@@ -1,501 +0,0 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import SendModal from '../../components/SendModal';
|
||||
import ReceiveModal from '../../components/ReceiveModal';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
TextInput,
|
||||
Image,
|
||||
} from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import Colors from '../../constants/colors';
|
||||
import { Typography, Spacing, BorderRadius, Shadow } from '../../constants/theme';
|
||||
|
||||
interface CoinRow {
|
||||
symbol: string;
|
||||
name: string;
|
||||
amount: string;
|
||||
network: string;
|
||||
icon: any;
|
||||
color: string;
|
||||
}
|
||||
|
||||
export default function WalletScreen({ navigation, route }: any) {
|
||||
const [withdrawalAddresses, setWithdrawalAddresses] = useState<{ [key: string]: string }>({});
|
||||
const [sendModalVisible, setSendModalVisible] = useState(false);
|
||||
const [receiveModalVisible, setReceiveModalVisible] = useState(false);
|
||||
const [selectedToken, setSelectedToken] = useState<CoinRow | null>(null);
|
||||
const [totalReward] = useState('50000');
|
||||
const [trustScore] = useState('150000');
|
||||
const [totalReferral] = useState('500');
|
||||
const [circleScore] = useState('30000');
|
||||
const [eduScore] = useState('1000');
|
||||
const [stakeAmount] = useState('1000');
|
||||
|
||||
const coins: CoinRow[] = [
|
||||
{
|
||||
symbol: 'PEZ',
|
||||
name: 'PezkuwiChain',
|
||||
amount: '100',
|
||||
network: 'op',
|
||||
icon: require('../../../assets/tokens/pez.png'),
|
||||
color: '#E8C896',
|
||||
},
|
||||
{
|
||||
symbol: 'HEZ',
|
||||
name: 'Hemwelatî',
|
||||
amount: '100',
|
||||
network: 'op',
|
||||
icon: require('../../../assets/tokens/hez.png'),
|
||||
color: '#98D8C8',
|
||||
},
|
||||
];
|
||||
|
||||
const handleWithdraw = (coin: CoinRow) => {
|
||||
setSelectedToken(coin);
|
||||
setSendModalVisible(true);
|
||||
};
|
||||
|
||||
const handleDeposit = (coin: CoinRow) => {
|
||||
setSelectedToken(coin);
|
||||
setReceiveModalVisible(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
{/* Colorful Top Band */}
|
||||
<View style={styles.topBand}>
|
||||
<View style={[styles.bandSegment, { backgroundColor: '#E74C3C' }]} />
|
||||
<View style={[styles.bandSegment, { backgroundColor: '#27AE60' }]} />
|
||||
<View style={[styles.bandSegment, { backgroundColor: '#3498DB' }]} />
|
||||
<View style={[styles.bandSegment, { backgroundColor: '#F39C12' }]} />
|
||||
</View>
|
||||
|
||||
<ScrollView style={styles.content} showsVerticalScrollIndicator={false}>
|
||||
<View style={styles.mainSection}>
|
||||
{/* NFT Card - Top Right */}
|
||||
<View style={styles.nftCard}>
|
||||
<View style={styles.nftHeader}>
|
||||
<Text style={styles.nftLabel}>NFT</Text>
|
||||
<Text style={styles.nftId}>123456784444444444444444912</Text>
|
||||
</View>
|
||||
<View style={styles.nftBody}>
|
||||
<View style={styles.nftAvatar}>
|
||||
<Ionicons name="person" size={40} color="#FFFFFF" />
|
||||
</View>
|
||||
<Text style={styles.nftName}>Satoshi Qazi M.</Text>
|
||||
</View>
|
||||
<View style={styles.nftFooter}>
|
||||
<Ionicons name="trophy" size={20} color="#D4A017" />
|
||||
<Text style={styles.nftRewardLabel}>TOTAL REWARD</Text>
|
||||
<Text style={styles.nftRewardValue}>{totalReward}</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Coins Table */}
|
||||
<View style={styles.tableContainer}>
|
||||
{/* Table Header */}
|
||||
<View style={styles.tableHeader}>
|
||||
<Text style={[styles.headerCell, { flex: 1 }]}>coin</Text>
|
||||
<Text style={[styles.headerCell, { flex: 1 }]}>amount</Text>
|
||||
<Text style={[styles.headerCell, { flex: 1 }]}>Network</Text>
|
||||
<Text style={[styles.headerCell, { flex: 3 }]}>Witdrawal adress</Text>
|
||||
<Text style={[styles.headerCell, { flex: 1.5 }]}>withdraw deposit</Text>
|
||||
</View>
|
||||
|
||||
{/* Table Rows */}
|
||||
{coins.map((coin) => (
|
||||
<View key={coin.symbol} style={styles.tableRow}>
|
||||
{/* Coin */}
|
||||
<View style={[styles.cell, { flex: 1 }]}>
|
||||
<Image source={coin.icon} style={styles.coinIcon} />
|
||||
<Text style={styles.coinSymbol}>{coin.symbol}</Text>
|
||||
</View>
|
||||
|
||||
{/* Amount */}
|
||||
<View style={[styles.cell, { flex: 1 }]}>
|
||||
<Text style={styles.cellText}>{coin.amount}</Text>
|
||||
</View>
|
||||
|
||||
{/* Network */}
|
||||
<View style={[styles.cell, { flex: 1 }]}>
|
||||
<Text style={styles.cellText}>{coin.network}</Text>
|
||||
</View>
|
||||
|
||||
{/* Withdrawal Address */}
|
||||
<View style={[styles.cell, { flex: 3 }]}>
|
||||
<TextInput
|
||||
style={styles.addressInput}
|
||||
placeholder="Withdrawal adresinizi yazin"
|
||||
placeholderTextColor="#999"
|
||||
value={withdrawalAddresses[coin.symbol] || ''}
|
||||
onChangeText={(text) =>
|
||||
setWithdrawalAddresses({ ...withdrawalAddresses, [coin.symbol]: text })
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* Withdraw/Deposit Buttons */}
|
||||
<View style={[styles.cell, { flex: 1.5, flexDirection: 'row', gap: 8 }]}>
|
||||
<TouchableOpacity
|
||||
style={styles.actionButton}
|
||||
onPress={() => handleWithdraw(coin)}
|
||||
>
|
||||
<View style={styles.withdrawButton}>
|
||||
<Ionicons name="arrow-down" size={20} color="#FFFFFF" />
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.actionButton}
|
||||
onPress={() => handleDeposit(coin)}
|
||||
>
|
||||
<View style={styles.depositButton}>
|
||||
<Ionicons name="arrow-up" size={20} color="#FFFFFF" />
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Bottom Stats Cards */}
|
||||
<View style={styles.statsSection}>
|
||||
{/* Stake/Unstake Card */}
|
||||
<View style={[styles.statsCard, { backgroundColor: '#FFFFFF' }]}>
|
||||
<TouchableOpacity style={styles.stakeButton}>
|
||||
<Text style={styles.stakeLabel}>STAKE</Text>
|
||||
<Text style={styles.stakeValue}>{stakeAmount}</Text>
|
||||
<View style={styles.stakeIcon}>
|
||||
<Ionicons name="arrow-up" size={16} color="#FFFFFF" />
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
|
||||
<View style={styles.stakeDivider} />
|
||||
|
||||
<TouchableOpacity style={styles.unstakeButton}>
|
||||
<Text style={styles.unstakeLabel}>UNSTAKE</Text>
|
||||
<Text style={styles.unstakeValue}>{stakeAmount}</Text>
|
||||
<View style={styles.unstakeIcon}>
|
||||
<Ionicons name="arrow-down" size={16} color="#FFFFFF" />
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Trust Score */}
|
||||
<TouchableOpacity
|
||||
style={[styles.statsCard, styles.scoreCard]}
|
||||
onPress={() => navigation.navigate('TrustScore')}
|
||||
>
|
||||
<Ionicons name="shield-checkmark" size={32} color="#D4A017" />
|
||||
<Text style={styles.scoreLabel}>TRUST SCORE</Text>
|
||||
<Text style={styles.scoreValue}>{trustScore}</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* Total Referral */}
|
||||
<TouchableOpacity
|
||||
style={[styles.statsCard, styles.scoreCard]}
|
||||
onPress={() => navigation.navigate('Referral')}
|
||||
>
|
||||
<Ionicons name="people" size={32} color="#D4A017" />
|
||||
<Text style={styles.scoreLabel}>TOTAL REFERAL</Text>
|
||||
<Text style={styles.scoreValue}>{totalReferral}</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* Circle Score */}
|
||||
<TouchableOpacity style={[styles.statsCard, styles.scoreCard]}>
|
||||
<Ionicons name="radio-button-on" size={32} color="#D4A017" />
|
||||
<Text style={styles.scoreLabel}>CIRCLE SCORE</Text>
|
||||
<Text style={styles.scoreValue}>{circleScore}</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* Edu Score */}
|
||||
<TouchableOpacity
|
||||
style={[styles.statsCard, styles.scoreCard]}
|
||||
onPress={() => navigation.navigate('Education')}
|
||||
>
|
||||
<Ionicons name="school" size={32} color="#D4A017" />
|
||||
<Text style={styles.scoreLabel}>EDU. SCORE</Text>
|
||||
<Text style={styles.scoreValue}>{eduScore}</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</ScrollView>
|
||||
|
||||
{/* Send Modal */}
|
||||
{selectedToken && (
|
||||
<SendModal
|
||||
visible={sendModalVisible}
|
||||
onClose={() => setSendModalVisible(false)}
|
||||
token={{
|
||||
symbol: selectedToken.symbol,
|
||||
name: selectedToken.name,
|
||||
balance: selectedToken.amount,
|
||||
icon: selectedToken.icon,
|
||||
color: selectedToken.color,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Receive Modal */}
|
||||
{selectedToken && (
|
||||
<ReceiveModal
|
||||
visible={receiveModalVisible}
|
||||
onClose={() => setReceiveModalVisible(false)}
|
||||
token={{
|
||||
symbol: selectedToken.symbol,
|
||||
name: selectedToken.name,
|
||||
icon: selectedToken.icon,
|
||||
color: selectedToken.color,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#E8F0F7',
|
||||
},
|
||||
topBand: {
|
||||
flexDirection: 'row',
|
||||
height: 8,
|
||||
},
|
||||
bandSegment: {
|
||||
flex: 1,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
},
|
||||
mainSection: {
|
||||
padding: Spacing.lg,
|
||||
position: 'relative',
|
||||
},
|
||||
nftCard: {
|
||||
position: 'absolute',
|
||||
top: Spacing.lg,
|
||||
right: Spacing.lg,
|
||||
width: 140,
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: BorderRadius.large,
|
||||
padding: Spacing.md,
|
||||
...Shadow.medium,
|
||||
zIndex: 10,
|
||||
},
|
||||
nftHeader: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: Spacing.sm,
|
||||
},
|
||||
nftLabel: {
|
||||
fontSize: 12,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
},
|
||||
nftId: {
|
||||
fontSize: 8,
|
||||
color: Colors.textGray,
|
||||
},
|
||||
nftBody: {
|
||||
alignItems: 'center',
|
||||
marginVertical: Spacing.sm,
|
||||
},
|
||||
nftAvatar: {
|
||||
width: 60,
|
||||
height: 60,
|
||||
borderRadius: 30,
|
||||
backgroundColor: Colors.teal,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginBottom: Spacing.xs,
|
||||
},
|
||||
nftName: {
|
||||
fontSize: 11,
|
||||
fontWeight: '600',
|
||||
color: Colors.textDark,
|
||||
textAlign: 'center',
|
||||
},
|
||||
nftFooter: {
|
||||
alignItems: 'center',
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: '#F0F0F0',
|
||||
paddingTop: Spacing.sm,
|
||||
},
|
||||
nftRewardLabel: {
|
||||
fontSize: 9,
|
||||
fontWeight: '600',
|
||||
color: Colors.textGray,
|
||||
marginTop: 4,
|
||||
},
|
||||
nftRewardValue: {
|
||||
fontSize: 16,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
marginTop: 2,
|
||||
},
|
||||
tableContainer: {
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: BorderRadius.large,
|
||||
padding: Spacing.md,
|
||||
marginRight: 160,
|
||||
...Shadow.small,
|
||||
},
|
||||
tableHeader: {
|
||||
flexDirection: 'row',
|
||||
paddingBottom: Spacing.sm,
|
||||
borderBottomWidth: 2,
|
||||
borderBottomColor: '#E0E0E0',
|
||||
marginBottom: Spacing.sm,
|
||||
},
|
||||
headerCell: {
|
||||
fontSize: 11,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
textAlign: 'center',
|
||||
},
|
||||
tableRow: {
|
||||
flexDirection: 'row',
|
||||
paddingVertical: Spacing.md,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#F0F0F0',
|
||||
alignItems: 'center',
|
||||
},
|
||||
cell: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
coinIcon: {
|
||||
width: 32,
|
||||
height: 32,
|
||||
marginBottom: 4,
|
||||
},
|
||||
coinSymbol: {
|
||||
fontSize: 12,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
marginTop: 2,
|
||||
},
|
||||
cellText: {
|
||||
fontSize: 12,
|
||||
fontWeight: '600',
|
||||
color: Colors.textDark,
|
||||
},
|
||||
addressInput: {
|
||||
flex: 1,
|
||||
backgroundColor: '#F5F5F5',
|
||||
borderRadius: BorderRadius.small,
|
||||
paddingHorizontal: Spacing.sm,
|
||||
paddingVertical: Spacing.xs,
|
||||
fontSize: 10,
|
||||
color: Colors.textDark,
|
||||
},
|
||||
actionButton: {
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: 8,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
withdrawButton: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundColor: '#E74C3C',
|
||||
borderRadius: 8,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
depositButton: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundColor: '#27AE60',
|
||||
borderRadius: 8,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
statsSection: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
padding: Spacing.lg,
|
||||
gap: Spacing.md,
|
||||
},
|
||||
statsCard: {
|
||||
backgroundColor: '#F5F5F5',
|
||||
borderRadius: BorderRadius.large,
|
||||
padding: Spacing.lg,
|
||||
...Shadow.small,
|
||||
},
|
||||
stakeButton: {
|
||||
alignItems: 'center',
|
||||
},
|
||||
stakeLabel: {
|
||||
fontSize: 12,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
},
|
||||
stakeValue: {
|
||||
fontSize: 18,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
marginVertical: Spacing.xs,
|
||||
},
|
||||
stakeIcon: {
|
||||
width: 28,
|
||||
height: 28,
|
||||
borderRadius: 14,
|
||||
backgroundColor: '#27AE60',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
stakeDivider: {
|
||||
height: 1,
|
||||
backgroundColor: '#E0E0E0',
|
||||
marginVertical: Spacing.md,
|
||||
},
|
||||
unstakeButton: {
|
||||
alignItems: 'center',
|
||||
},
|
||||
unstakeLabel: {
|
||||
fontSize: 12,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
},
|
||||
unstakeValue: {
|
||||
fontSize: 18,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
marginVertical: Spacing.xs,
|
||||
},
|
||||
unstakeIcon: {
|
||||
width: 28,
|
||||
height: 28,
|
||||
borderRadius: 14,
|
||||
backgroundColor: '#E74C3C',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
scoreCard: {
|
||||
alignItems: 'center',
|
||||
minWidth: 110,
|
||||
},
|
||||
scoreLabel: {
|
||||
fontSize: 10,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
marginTop: Spacing.sm,
|
||||
textAlign: 'center',
|
||||
},
|
||||
scoreValue: {
|
||||
fontSize: 20,
|
||||
fontWeight: '700',
|
||||
color: Colors.textDark,
|
||||
marginTop: Spacing.xs,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
import React from 'react';
|
||||
import { View, Text, StyleSheet, TouchableOpacity, ScrollView, SafeAreaView } from 'react-native';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import Colors from '../../constants/colors';
|
||||
import { Typography, Spacing, BorderRadius, Shadow } from '../../constants/theme';
|
||||
|
||||
export default function WalletScreen({ navigation }: any) {
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<ScrollView showsVerticalScrollIndicator={false}>
|
||||
<Text style={styles.title}>Wallet</Text>
|
||||
|
||||
{/* HEZ Card */}
|
||||
<LinearGradient
|
||||
colors={Colors.gradients.hezCard}
|
||||
style={styles.tokenCard}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
>
|
||||
<View style={styles.tokenHeader}>
|
||||
<Text style={styles.tokenName}>HEZ</Text>
|
||||
<Text style={styles.tokenSubtitle}>The People's Currency</Text>
|
||||
</View>
|
||||
<Text style={styles.tokenBalance}>45,750.5</Text>
|
||||
<Text style={styles.tokenUsd}>$45,234 USD</Text>
|
||||
<Text style={styles.tokenStaked}>Staked: 30,000 HEZ</Text>
|
||||
</LinearGradient>
|
||||
|
||||
{/* PEZ Card */}
|
||||
<LinearGradient
|
||||
colors={Colors.gradients.pezCard}
|
||||
style={styles.tokenCard}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
>
|
||||
<View style={styles.tokenHeader}>
|
||||
<Text style={styles.tokenName}>PEZ</Text>
|
||||
<Text style={styles.tokenSubtitle}>Governance Token</Text>
|
||||
</View>
|
||||
<Text style={styles.tokenBalance}>1,234,567</Text>
|
||||
<Text style={styles.tokenUsd}>$123,456 USD</Text>
|
||||
<Text style={styles.tokenStaked}>Governance Power: 2.5%</Text>
|
||||
</LinearGradient>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<View style={styles.actions}>
|
||||
<TouchableOpacity style={[styles.actionButton, { backgroundColor: Colors.peach }]}>
|
||||
<Ionicons name="arrow-forward" size={24} color="#FFFFFF" />
|
||||
<Text style={styles.actionText}>Send</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={[styles.actionButton, { backgroundColor: Colors.teal }]}>
|
||||
<Ionicons name="arrow-down" size={24} color="#FFFFFF" />
|
||||
<Text style={styles.actionText}>Receive</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Transactions */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Recent Transactions</Text>
|
||||
<View style={styles.transactionItem}>
|
||||
<View style={styles.transactionIcon}>
|
||||
<Ionicons name="arrow-forward" size={20} color={Colors.coral} />
|
||||
</View>
|
||||
<View style={styles.transactionInfo}>
|
||||
<Text style={styles.transactionTitle}>Sent HEZ</Text>
|
||||
<Text style={styles.transactionDate}>Yesterday</Text>
|
||||
</View>
|
||||
<Text style={styles.transactionAmount}>-500 HEZ</Text>
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: { flex: 1, backgroundColor: Colors.background },
|
||||
title: { fontSize: 28, fontWeight: '700', color: Colors.textDark, padding: 20 },
|
||||
tokenCard: { margin: 20, padding: 24, borderRadius: 20, ...Shadow.soft },
|
||||
tokenHeader: { marginBottom: 16 },
|
||||
tokenName: { fontSize: 24, fontWeight: '700', color: '#FFFFFF' },
|
||||
tokenSubtitle: { fontSize: 14, color: 'rgba(255,255,255,0.8)' },
|
||||
tokenBalance: { fontSize: 36, fontWeight: '700', color: '#FFFFFF', marginBottom: 8 },
|
||||
tokenUsd: { fontSize: 18, color: 'rgba(255,255,255,0.9)', marginBottom: 8 },
|
||||
tokenStaked: { fontSize: 14, color: 'rgba(255,255,255,0.8)' },
|
||||
actions: { flexDirection: 'row', paddingHorizontal: 20, gap: 12 },
|
||||
actionButton: { flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', padding: 16, borderRadius: 16, gap: 8 },
|
||||
actionText: { fontSize: 16, fontWeight: '600', color: '#FFFFFF' },
|
||||
section: { padding: 20 },
|
||||
sectionTitle: { fontSize: 18, fontWeight: '600', color: Colors.textDark, marginBottom: 16 },
|
||||
transactionItem: { flexDirection: 'row', alignItems: 'center', backgroundColor: Colors.card, padding: 16, borderRadius: 12, marginBottom: 12 },
|
||||
transactionIcon: { width: 40, height: 40, borderRadius: 20, backgroundColor: Colors.background, justifyContent: 'center', alignItems: 'center', marginRight: 12 },
|
||||
transactionInfo: { flex: 1 },
|
||||
transactionTitle: { fontSize: 16, fontWeight: '600', color: Colors.textDark },
|
||||
transactionDate: { fontSize: 14, color: Colors.textGray, marginTop: 4 },
|
||||
transactionAmount: { fontSize: 16, fontWeight: '600', color: Colors.coral },
|
||||
});
|
||||
@@ -1,223 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
SafeAreaView,
|
||||
TextInput,
|
||||
Alert,
|
||||
} from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { usePolkadot } from '../../contexts/PolkadotContext';
|
||||
|
||||
export default function WalletSetupScreen({ navigation }: any) {
|
||||
const { saveAccount } = usePolkadot();
|
||||
const [walletAddress, setWalletAddress] = useState('5DFwqK698vL4gXHEcanaewnAqhxJ2rjhAogpSTHw3iwGDwd3');
|
||||
const [walletName, setWalletName] = useState('My Wallet');
|
||||
|
||||
const handleConnectWithAddress = async () => {
|
||||
if (!walletAddress.trim()) {
|
||||
Alert.alert('Error', 'Please enter a valid wallet address');
|
||||
return;
|
||||
}
|
||||
|
||||
// Save the account
|
||||
await saveAccount({
|
||||
address: walletAddress.trim(),
|
||||
name: walletName.trim() || 'My Wallet',
|
||||
});
|
||||
|
||||
navigation.navigate('MainTabs');
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<LinearGradient
|
||||
colors={['#F08080', '#E8C896', '#F5B895']}
|
||||
style={styles.gradient}
|
||||
>
|
||||
<View style={styles.content}>
|
||||
{/* Header */}
|
||||
<View style={styles.header}>
|
||||
<Ionicons name="wallet" size={80} color="#FFF" />
|
||||
<Text style={styles.title}>Connect Your Wallet</Text>
|
||||
<Text style={styles.subtitle}>
|
||||
Enter your PezkuwiChain wallet address to get started
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* Main Card */}
|
||||
<View style={styles.card}>
|
||||
<View style={styles.optionHeader}>
|
||||
<Ionicons name="key" size={32} color="#F08080" />
|
||||
<Text style={styles.optionTitle}>Wallet Details</Text>
|
||||
</View>
|
||||
|
||||
<Text style={styles.label}>Wallet Name (optional)</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="My Wallet"
|
||||
value={walletName}
|
||||
onChangeText={setWalletName}
|
||||
placeholderTextColor="#999"
|
||||
/>
|
||||
|
||||
<Text style={styles.label}>Wallet Address</Text>
|
||||
<TextInput
|
||||
style={[styles.input, styles.addressInput]}
|
||||
placeholder="5GrwvaEF5zXb26Fz9rcQpDWS..."
|
||||
value={walletAddress}
|
||||
onChangeText={setWalletAddress}
|
||||
placeholderTextColor="#999"
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
multiline
|
||||
numberOfLines={2}
|
||||
/>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.primaryButton}
|
||||
onPress={handleConnectWithAddress}
|
||||
>
|
||||
<Text style={styles.primaryButtonText}>Continue</Text>
|
||||
<Ionicons name="arrow-forward" size={20} color="#FFF" />
|
||||
</TouchableOpacity>
|
||||
|
||||
<View style={styles.infoBox}>
|
||||
<Ionicons name="information-circle" size={20} color="#7DD3C0" />
|
||||
<Text style={styles.infoText}>
|
||||
Your wallet address is only stored locally on your device. We never access your private keys.
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Footer */}
|
||||
<View style={styles.footer}>
|
||||
<Ionicons name="shield-checkmark" size={20} color="#FFF" />
|
||||
<Text style={styles.footerText}>
|
||||
All blockchain data fetched securely via backend API
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
gradient: {
|
||||
flex: 1,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
padding: 20,
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
header: {
|
||||
alignItems: 'center',
|
||||
marginTop: 40,
|
||||
},
|
||||
title: {
|
||||
fontSize: 28,
|
||||
fontWeight: 'bold',
|
||||
color: '#FFF',
|
||||
marginTop: 20,
|
||||
textAlign: 'center',
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 16,
|
||||
color: '#FFF',
|
||||
marginTop: 12,
|
||||
textAlign: 'center',
|
||||
opacity: 0.9,
|
||||
paddingHorizontal: 20,
|
||||
},
|
||||
card: {
|
||||
backgroundColor: '#FFF',
|
||||
borderRadius: 24,
|
||||
padding: 24,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 4 },
|
||||
shadowOpacity: 0.15,
|
||||
shadowRadius: 12,
|
||||
elevation: 8,
|
||||
},
|
||||
optionHeader: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 12,
|
||||
marginBottom: 20,
|
||||
},
|
||||
optionTitle: {
|
||||
fontSize: 20,
|
||||
fontWeight: '700',
|
||||
color: '#333',
|
||||
},
|
||||
label: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: '#666',
|
||||
marginBottom: 8,
|
||||
marginTop: 12,
|
||||
},
|
||||
input: {
|
||||
backgroundColor: '#F5F5F5',
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
fontSize: 14,
|
||||
color: '#333',
|
||||
},
|
||||
addressInput: {
|
||||
minHeight: 60,
|
||||
textAlignVertical: 'top',
|
||||
},
|
||||
primaryButton: {
|
||||
backgroundColor: '#F08080',
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: 8,
|
||||
marginTop: 20,
|
||||
},
|
||||
primaryButtonText: {
|
||||
color: '#FFF',
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
},
|
||||
infoBox: {
|
||||
backgroundColor: '#F0F9F7',
|
||||
borderRadius: 12,
|
||||
padding: 12,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-start',
|
||||
gap: 8,
|
||||
marginTop: 16,
|
||||
borderWidth: 1,
|
||||
borderColor: '#D0F0E8',
|
||||
},
|
||||
infoText: {
|
||||
flex: 1,
|
||||
fontSize: 12,
|
||||
color: '#5DBEA3',
|
||||
lineHeight: 16,
|
||||
},
|
||||
footer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: 8,
|
||||
marginBottom: 20,
|
||||
},
|
||||
footerText: {
|
||||
fontSize: 12,
|
||||
color: '#FFF',
|
||||
opacity: 0.9,
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user