mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-04-28 06:07:57 +00:00
chore: migrate git dependencies to Gitea mirror (git.pezkuwichain.io)
This commit is contained in:
@@ -0,0 +1,856 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
StyleSheet,
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
StatusBar,
|
||||
Image,
|
||||
Alert,
|
||||
Dimensions,
|
||||
Platform,
|
||||
ActivityIndicator,
|
||||
ImageSourcePropType,
|
||||
RefreshControl,
|
||||
} from 'react-native';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import type { NavigationProp } from '@react-navigation/native';
|
||||
import type { BottomTabParamList } from '../../navigation/BottomTabNavigator';
|
||||
import type { RootStackParamList } from '../../navigation/AppNavigator';
|
||||
import { KurdistanColors } from '../../theme/colors';
|
||||
import { useAuth } from '../../contexts/AuthContext';
|
||||
import { usePezkuwi } from '../../contexts/PezkuwiContext';
|
||||
import { supabase } from '../../lib/supabase';
|
||||
import AvatarPickerModal from '../../components/AvatarPickerModal';
|
||||
import { NotificationCenterModal } from '../../components/NotificationCenterModal';
|
||||
import { fetchUserTikis, getPrimaryRole, getTikiDisplayName, getTikiEmoji } from '../../../shared/lib/tiki';
|
||||
import { getAllScores, type UserScores } from '../../../shared/lib/scores';
|
||||
import { getKycStatus } from '../../../shared/lib/kyc';
|
||||
|
||||
// Existing Quick Action Images (Reused)
|
||||
import qaEducation from '../../../shared/images/quick-actions/qa_education.png';
|
||||
import qaExchange from '../../../shared/images/quick-actions/qa_exchange.png';
|
||||
import qaForum from '../../../shared/images/quick-actions/qa_forum.jpg';
|
||||
import qaGovernance from '../../../shared/images/quick-actions/qa_governance.jpg';
|
||||
import qaTrading from '../../../shared/images/quick-actions/qa_trading.jpg';
|
||||
import qaB2B from '../../../shared/images/quick-actions/qa_b2b.png';
|
||||
import qaBank from '../../../shared/images/quick-actions/qa_bank.png';
|
||||
import _qaGames from '../../../shared/images/quick-actions/qa_games.png';
|
||||
import qaKurdMedia from '../../../shared/images/quick-actions/qa_kurdmedia.jpg';
|
||||
import qaUniversity from '../../../shared/images/quick-actions/qa_university.png';
|
||||
import avatarPlaceholder from '../../../shared/images/app-image.png'; // Fallback avatar
|
||||
import { logger } from '../../utils/logger';
|
||||
|
||||
const { width: _width } = Dimensions.get('window');
|
||||
|
||||
// Avatar pool matching AvatarPickerModal
|
||||
const AVATAR_POOL = [
|
||||
{ id: 'avatar1', emoji: '👨🏻' },
|
||||
{ id: 'avatar2', emoji: '👨🏼' },
|
||||
{ id: 'avatar3', emoji: '👨🏽' },
|
||||
{ id: 'avatar4', emoji: '👨🏾' },
|
||||
{ id: 'avatar5', emoji: '👩🏻' },
|
||||
{ id: 'avatar6', emoji: '👩🏼' },
|
||||
{ id: 'avatar7', emoji: '👩🏽' },
|
||||
{ id: 'avatar8', emoji: '👩🏾' },
|
||||
{ id: 'avatar9', emoji: '🧔🏻' },
|
||||
{ id: 'avatar10', emoji: '🧔🏼' },
|
||||
{ id: 'avatar11', emoji: '🧔🏽' },
|
||||
{ id: 'avatar12', emoji: '🧔🏾' },
|
||||
{ id: 'avatar13', emoji: '👳🏻♂️' },
|
||||
{ id: 'avatar14', emoji: '👳🏼♂️' },
|
||||
{ id: 'avatar15', emoji: '👳🏽♂️' },
|
||||
{ id: 'avatar16', emoji: '🧕🏻' },
|
||||
{ id: 'avatar17', emoji: '🧕🏼' },
|
||||
{ id: 'avatar18', emoji: '🧕🏽' },
|
||||
{ id: 'avatar19', emoji: '👴🏻' },
|
||||
{ id: 'avatar20', emoji: '👴🏼' },
|
||||
{ id: 'avatar21', emoji: '👵🏻' },
|
||||
{ id: 'avatar22', emoji: '👵🏼' },
|
||||
{ id: 'avatar23', emoji: '👦🏻' },
|
||||
{ id: 'avatar24', emoji: '👦🏼' },
|
||||
{ id: 'avatar25', emoji: '👧🏻' },
|
||||
{ id: 'avatar26', emoji: '👧🏼' },
|
||||
];
|
||||
|
||||
// Helper function to get emoji from avatar ID
|
||||
const getEmojiFromAvatarId = (avatarId: string): string => {
|
||||
const avatar = AVATAR_POOL.find(a => a.id === avatarId);
|
||||
return avatar ? avatar.emoji : '👤'; // Default to person emoji if not found
|
||||
};
|
||||
|
||||
type DashboardScreenProps = Record<string, never>;
|
||||
|
||||
interface ProfileData {
|
||||
id?: string;
|
||||
full_name?: string | null;
|
||||
avatar_url?: string | null;
|
||||
created_at?: string;
|
||||
}
|
||||
|
||||
const DashboardScreen: React.FC<DashboardScreenProps> = () => {
|
||||
const navigation = useNavigation<NavigationProp<BottomTabParamList & RootStackParamList>>();
|
||||
const { user } = useAuth();
|
||||
const { api, isApiReady, selectedAccount, accounts, connectWallet } = usePezkuwi();
|
||||
const [profileData, setProfileData] = useState<ProfileData | null>(null);
|
||||
const [_loading, setLoading] = useState(true);
|
||||
const [avatarModalVisible, setAvatarModalVisible] = useState(false);
|
||||
const [notificationModalVisible, setNotificationModalVisible] = useState(false);
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
|
||||
// Blockchain state
|
||||
const [tikis, setTikis] = useState<string[]>([]);
|
||||
const [scores, setScores] = useState<UserScores>({
|
||||
trustScore: 0,
|
||||
referralScore: 0,
|
||||
stakingScore: 0,
|
||||
tikiScore: 0,
|
||||
totalScore: 0
|
||||
});
|
||||
const [kycStatus, setKycStatus] = useState<string>('NotStarted');
|
||||
const [loadingScores, setLoadingScores] = useState(false);
|
||||
|
||||
// Fetch profile data from Supabase
|
||||
const fetchProfile = useCallback(async () => {
|
||||
if (!user) {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const { data, error } = await supabase
|
||||
.from('profiles')
|
||||
.select('*')
|
||||
.eq('id', user.id)
|
||||
.maybeSingle();
|
||||
|
||||
if (error) {
|
||||
logger.warn('Profile fetch error:', error);
|
||||
return;
|
||||
}
|
||||
|
||||
setProfileData(data);
|
||||
} catch (error) {
|
||||
logger.error('Error fetching profile:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [user]);
|
||||
|
||||
// Fetch blockchain data (tikis, scores, KYC)
|
||||
const fetchBlockchainData = useCallback(async () => {
|
||||
if (!selectedAccount || !api || !isApiReady) return;
|
||||
|
||||
setLoadingScores(true);
|
||||
try {
|
||||
// Fetch tikis
|
||||
const userTikis = await fetchUserTikis(api, selectedAccount.address);
|
||||
setTikis(userTikis);
|
||||
|
||||
// Fetch all scores
|
||||
const allScores = await getAllScores(api, selectedAccount.address);
|
||||
setScores(allScores);
|
||||
|
||||
// Fetch KYC status
|
||||
const status = await getKycStatus(api, selectedAccount.address);
|
||||
setKycStatus(status);
|
||||
|
||||
logger.warn('[Dashboard] Blockchain data fetched:', { tikis: userTikis, scores: allScores, kycStatus: status });
|
||||
} catch (error) {
|
||||
logger.error('[Dashboard] Error fetching blockchain data:', error);
|
||||
} finally {
|
||||
setLoadingScores(false);
|
||||
}
|
||||
}, [selectedAccount, api, isApiReady]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchProfile();
|
||||
}, [fetchProfile]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedAccount && api && isApiReady) {
|
||||
fetchBlockchainData();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [fetchBlockchainData]);
|
||||
|
||||
// Check if user is a visitor (default when no blockchain wallet or no tikis)
|
||||
const _isVisitor = !selectedAccount || tikis.length === 0;
|
||||
|
||||
// Handle wallet connection
|
||||
const handleConnectWallet = async () => {
|
||||
if (accounts.length === 0) {
|
||||
navigation.navigate('WalletSetup');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await connectWallet();
|
||||
Alert.alert('Girêdayî / Connected', 'Cîzdanê te bi serkeftî girêdayî bû!\nYour wallet has been connected successfully!');
|
||||
} catch (error) {
|
||||
logger.error('Wallet connection error:', error);
|
||||
Alert.alert('Çewtî / Error', 'Cîzdan nehat girêdan.\nFailed to connect wallet.');
|
||||
}
|
||||
};
|
||||
const primaryRole = tikis.length > 0 ? getPrimaryRole(tikis) : 'Visitor';
|
||||
|
||||
const _showComingSoon = (featureName: string) => {
|
||||
Alert.alert(
|
||||
'Coming Soon',
|
||||
`${featureName} will be available soon!`,
|
||||
[{ text: 'OK' }]
|
||||
);
|
||||
};
|
||||
|
||||
const _showAwaitingGovernment = () => {
|
||||
Alert.alert(
|
||||
'Li benda damezrandinê / Awaiting Establishment',
|
||||
'Duaye helbejartina hukumeta Komara Dijitaliya Kurdistanê yên beta damezrandin.\n\nAwaiting the beta elections and establishment of the Digital Kurdistan Republic government.',
|
||||
[{ text: 'Temam / OK' }]
|
||||
);
|
||||
};
|
||||
|
||||
const _showUnderMaintenance = () => {
|
||||
Alert.alert(
|
||||
'Di bin çêkirinê de ye / Under Maintenance',
|
||||
'Ev taybetmendî niha di bin çêkirinê de ye. Ji kerema xwe paşê vegerin.\n\nThis feature is currently under maintenance. Please check back later.',
|
||||
[{ text: 'Temam / OK' }]
|
||||
);
|
||||
};
|
||||
|
||||
const _showAwaitingSerokElection = () => {
|
||||
Alert.alert(
|
||||
'Li benda hilbijartinên çalak / Awaiting Active Elections',
|
||||
'Duaye hilbijartinên Serokî yên çalak bibin.\n\nAwaiting active Presidential elections to be initiated.',
|
||||
[{ text: 'Temam / OK' }]
|
||||
);
|
||||
};
|
||||
|
||||
const _showAwaitingMinistryOfEducation = () => {
|
||||
Alert.alert(
|
||||
'Li benda Wezareta Perwerdê / Awaiting Ministry of Education',
|
||||
'Duaye damezrandina Wezareta Perwerdê yên aktîv bibin.\n\nAwaiting the establishment of an active Ministry of Education.',
|
||||
[{ text: 'Temam / OK' }]
|
||||
);
|
||||
};
|
||||
|
||||
const handleAvatarClick = () => {
|
||||
setAvatarModalVisible(true);
|
||||
};
|
||||
|
||||
const handleAvatarSelected = (avatarUrl: string) => {
|
||||
// Refresh profile data to show new avatar
|
||||
setProfileData((prev: ProfileData | null) => ({
|
||||
...prev,
|
||||
avatar_url: avatarUrl,
|
||||
}));
|
||||
};
|
||||
|
||||
const renderAppIcon = (title: string, icon: string | ImageSourcePropType, onPress: () => void, isEmoji = false, comingSoon = false) => (
|
||||
<TouchableOpacity
|
||||
style={styles.appIconContainer}
|
||||
onPress={onPress}
|
||||
activeOpacity={0.7}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={`${title}${comingSoon ? ', coming soon' : ''}`}
|
||||
>
|
||||
<View style={[styles.appIconBox, comingSoon && styles.appIconDisabled]}>
|
||||
{isEmoji ? (
|
||||
<Text style={styles.emojiIcon}>{icon as string}</Text>
|
||||
) : (
|
||||
<Image source={icon as ImageSourcePropType} style={styles.imageIcon} resizeMode="cover" accessibilityLabel={`${title} icon`} />
|
||||
)}
|
||||
{comingSoon && (
|
||||
<View style={styles.lockBadge}>
|
||||
<Text style={styles.lockText}>🔒</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<Text style={styles.appIconTitle} numberOfLines={1}>{title}</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<StatusBar barStyle="light-content" backgroundColor={KurdistanColors.kesk} />
|
||||
|
||||
{/* HEADER SECTION */}
|
||||
<LinearGradient
|
||||
colors={[KurdistanColors.kesk, '#008f43']}
|
||||
style={styles.header}
|
||||
>
|
||||
<View style={styles.headerTop}>
|
||||
<View style={styles.avatarSection}>
|
||||
<TouchableOpacity onPress={handleAvatarClick} accessibilityRole="button" accessibilityLabel="Change profile avatar">
|
||||
{profileData?.avatar_url ? (
|
||||
// Check if avatar_url is a URL (starts with http) or an emoji ID
|
||||
profileData.avatar_url.startsWith('http') ? (
|
||||
<Image
|
||||
source={{ uri: profileData.avatar_url }}
|
||||
style={styles.avatar}
|
||||
accessibilityLabel="Profile avatar"
|
||||
/>
|
||||
) : (
|
||||
// It's an emoji ID, render as emoji text
|
||||
<View style={styles.avatar}>
|
||||
<Text style={styles.avatarEmoji}>
|
||||
{getEmojiFromAvatarId(profileData.avatar_url)}
|
||||
</Text>
|
||||
</View>
|
||||
)
|
||||
) : (
|
||||
<Image
|
||||
source={avatarPlaceholder}
|
||||
style={styles.avatar}
|
||||
accessibilityLabel="Profile avatar placeholder"
|
||||
/>
|
||||
)}
|
||||
{/* Online Status Indicator */}
|
||||
<View style={styles.statusIndicator} />
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* Tiki Badge next to avatar - shows primary role */}
|
||||
<View style={styles.tikiAvatarBadge}>
|
||||
<Text style={styles.tikiAvatarText}>
|
||||
{getTikiEmoji(primaryRole)} {getTikiDisplayName(primaryRole)}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.headerInfo}>
|
||||
<Text style={styles.greeting}>
|
||||
Rojbaş, {profileData?.full_name || user?.email?.split('@')[0] || 'Heval'}
|
||||
</Text>
|
||||
<View style={styles.tikiContainer}>
|
||||
{tikis.map((tiki, index) => (
|
||||
<View key={index} style={styles.tikiBadge}>
|
||||
<Text style={styles.tikiText}>✓ {tiki}</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.headerActions}>
|
||||
<TouchableOpacity style={styles.iconButton} onPress={() => setNotificationModalVisible(true)} accessibilityRole="button" accessibilityLabel="Open notifications">
|
||||
<Text style={styles.headerIcon}>🔔</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={styles.iconButton} onPress={() => navigation.navigate('Settings')} accessibilityRole="button" accessibilityLabel="Open settings">
|
||||
<Text style={styles.headerIcon}>⚙️</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
|
||||
<ScrollView
|
||||
showsVerticalScrollIndicator={false}
|
||||
contentContainerStyle={styles.scrollContent}
|
||||
style={styles.scrollView}
|
||||
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={() => { setRefreshing(true); Promise.all([fetchProfile(), fetchBlockchainData()]).finally(() => setRefreshing(false)); }} />}
|
||||
>
|
||||
{/* SCORE CARDS SECTION */}
|
||||
<View style={styles.scoreCardsContainer}>
|
||||
<ScrollView
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
contentContainerStyle={styles.scoreCardsContent}
|
||||
>
|
||||
{/* Member Since Card */}
|
||||
<View style={[styles.scoreCard, { borderLeftColor: KurdistanColors.kesk }]}>
|
||||
<Text style={styles.scoreCardIcon}>📅</Text>
|
||||
<Text style={styles.scoreCardLabel}>Member Since</Text>
|
||||
<Text style={styles.scoreCardValue}>
|
||||
{profileData?.created_at
|
||||
? new Date(profileData.created_at).toLocaleDateString('en-US', { month: 'short', year: 'numeric' })
|
||||
: user?.created_at
|
||||
? new Date(user.created_at).toLocaleDateString('en-US', { month: 'short', year: 'numeric' })
|
||||
: 'N/A'
|
||||
}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* Role Card */}
|
||||
<View style={[styles.scoreCard, { borderLeftColor: '#FF9800' }]}>
|
||||
<Text style={styles.scoreCardIcon}>{getTikiEmoji(primaryRole)}</Text>
|
||||
<Text style={styles.scoreCardLabel}>Role</Text>
|
||||
<Text style={styles.scoreCardValue}>{getTikiDisplayName(primaryRole)}</Text>
|
||||
<Text style={styles.scoreCardSubtext}>
|
||||
{selectedAccount ? `${tikis.length} ${tikis.length === 1 ? 'role' : 'roles'}` : 'Connect wallet'}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* Total Score Card */}
|
||||
<View style={[styles.scoreCard, { borderLeftColor: '#9C27B0' }]}>
|
||||
<Text style={styles.scoreCardIcon}>🏆</Text>
|
||||
<Text style={styles.scoreCardLabel}>Total Score</Text>
|
||||
{loadingScores ? (
|
||||
<ActivityIndicator size="small" color="#9C27B0" />
|
||||
) : (
|
||||
<>
|
||||
<Text style={[styles.scoreCardValue, { color: '#9C27B0' }]}>
|
||||
{scores.totalScore}
|
||||
</Text>
|
||||
<Text style={styles.scoreCardSubtext}>All score types</Text>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* Trust Score Card */}
|
||||
<View style={[styles.scoreCard, { borderLeftColor: '#9C27B0' }]}>
|
||||
<Text style={styles.scoreCardIcon}>🛡️</Text>
|
||||
<Text style={styles.scoreCardLabel}>Trust Score</Text>
|
||||
{loadingScores ? (
|
||||
<ActivityIndicator size="small" color="#9C27B0" />
|
||||
) : (
|
||||
<>
|
||||
<Text style={[styles.scoreCardValue, { color: '#9C27B0' }]}>
|
||||
{scores.trustScore}
|
||||
</Text>
|
||||
<Text style={styles.scoreCardSubtext}>pezpallet_trust</Text>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* Referral Score Card */}
|
||||
<View style={[styles.scoreCard, { borderLeftColor: '#00BCD4' }]}>
|
||||
<Text style={styles.scoreCardIcon}>👥</Text>
|
||||
<Text style={styles.scoreCardLabel}>Referral Score</Text>
|
||||
{loadingScores ? (
|
||||
<ActivityIndicator size="small" color="#00BCD4" />
|
||||
) : (
|
||||
<>
|
||||
<Text style={[styles.scoreCardValue, { color: '#00BCD4' }]}>
|
||||
{scores.referralScore}
|
||||
</Text>
|
||||
<Text style={styles.scoreCardSubtext}>Referrals</Text>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* Staking Score Card */}
|
||||
<View style={[styles.scoreCard, { borderLeftColor: '#4CAF50' }]}>
|
||||
<Text style={styles.scoreCardIcon}>📈</Text>
|
||||
<Text style={styles.scoreCardLabel}>Staking Score</Text>
|
||||
{loadingScores ? (
|
||||
<ActivityIndicator size="small" color="#4CAF50" />
|
||||
) : (
|
||||
<>
|
||||
<Text style={[styles.scoreCardValue, { color: '#4CAF50' }]}>
|
||||
{scores.stakingScore}
|
||||
</Text>
|
||||
<Text style={styles.scoreCardSubtext}>pezpallet_staking</Text>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* Tiki Score Card */}
|
||||
<View style={[styles.scoreCard, { borderLeftColor: '#E91E63' }]}>
|
||||
<Text style={styles.scoreCardIcon}>⭐</Text>
|
||||
<Text style={styles.scoreCardLabel}>Tiki Score</Text>
|
||||
{loadingScores ? (
|
||||
<ActivityIndicator size="small" color="#E91E63" />
|
||||
) : (
|
||||
<>
|
||||
<Text style={[styles.scoreCardValue, { color: '#E91E63' }]}>
|
||||
{scores.tikiScore}
|
||||
</Text>
|
||||
<Text style={styles.scoreCardSubtext}>
|
||||
{tikis.length} {tikis.length === 1 ? 'role' : 'roles'}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* KYC Status Card */}
|
||||
<View style={[styles.scoreCard, { borderLeftColor: kycStatus === 'Approved' ? '#4CAF50' : '#FFC107' }]}>
|
||||
<Text style={styles.scoreCardIcon}>
|
||||
{kycStatus === 'Approved' ? '✅' : kycStatus === 'Pending' ? '⏳' : '📝'}
|
||||
</Text>
|
||||
<Text style={styles.scoreCardLabel}>KYC Status</Text>
|
||||
<Text style={[styles.scoreCardValue, {
|
||||
color: kycStatus === 'Approved' ? '#4CAF50' : kycStatus === 'Pending' ? '#FFC107' : '#999',
|
||||
fontSize: 14
|
||||
}]}>
|
||||
{kycStatus}
|
||||
</Text>
|
||||
{kycStatus === 'NotStarted' && (
|
||||
<TouchableOpacity
|
||||
style={styles.kycButton}
|
||||
onPress={() => navigation.navigate('BeCitizenChoice')}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Apply for KYC verification"
|
||||
>
|
||||
<Text style={styles.kycButtonText}>Apply</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
|
||||
{/* 1. FINANCE SECTION */}
|
||||
<View style={styles.sectionContainer}>
|
||||
<View style={[styles.sectionHeader, { borderLeftColor: KurdistanColors.kesk }]}>
|
||||
<View style={styles.sectionTitleRow}>
|
||||
<Text style={styles.sectionTitle}>FINANCE 💰</Text>
|
||||
{/* Connect Wallet Button */}
|
||||
{!selectedAccount && (
|
||||
<TouchableOpacity
|
||||
style={styles.connectWalletBadge}
|
||||
onPress={handleConnectWallet}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Connect wallet"
|
||||
>
|
||||
<Text style={styles.connectWalletIcon}>👛</Text>
|
||||
<Text style={styles.connectWalletText}>Girêde</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
<TouchableOpacity onPress={() => navigation.navigate('Apps')} accessibilityRole="button" accessibilityLabel="See all finance apps">
|
||||
<Text style={styles.seeAllText}>Hemû / All</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={styles.appsGrid}>
|
||||
{/* Wallet - Navigate to WalletScreen */}
|
||||
{renderAppIcon('Wallet', '👛', () => navigation.navigate('Wallet'), true)}
|
||||
|
||||
{renderAppIcon('Bank', qaBank, () => navigation.navigate('Bank'), false, true)}
|
||||
{renderAppIcon('Exchange', qaExchange, () => navigation.navigate('Swap'), false)}
|
||||
{renderAppIcon('P2P', qaTrading, () => navigation.navigate('P2P'), false)}
|
||||
{renderAppIcon('B2B', qaB2B, () => navigation.navigate('B2B'), false, true)}
|
||||
{renderAppIcon('Bac/Zekat', '📊', () => navigation.navigate('TaxZekat'), true)}
|
||||
{renderAppIcon('Launchpad', '🚀', () => navigation.navigate('Launchpad'), true, true)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 2. GOVERNANCE SECTION */}
|
||||
<View style={styles.sectionContainer}>
|
||||
<View style={[styles.sectionHeader, { borderLeftColor: KurdistanColors.sor }]}>
|
||||
<Text style={styles.sectionTitle}>GOVERNANCE 🏛️</Text>
|
||||
</View>
|
||||
<View style={styles.appsGrid}>
|
||||
{renderAppIcon('President', '👑', () => navigation.navigate('President'), true)}
|
||||
{renderAppIcon('Assembly', qaGovernance, () => navigation.navigate('Assembly'), false, true)}
|
||||
{renderAppIcon('Vote', '🗳️', () => navigation.navigate('Vote'), true)}
|
||||
{renderAppIcon('Validators', '🛡️', () => navigation.navigate('Validators'), true)}
|
||||
{renderAppIcon('Justice', '⚖️', () => navigation.navigate('Justice'), true, true)}
|
||||
{renderAppIcon('Proposals', '📜', () => navigation.navigate('Proposals'), true)}
|
||||
{renderAppIcon('Polls', '📊', () => navigation.navigate('Polls'), true, true)}
|
||||
{renderAppIcon('Identity', '🆔', () => navigation.navigate('Identity'), true)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 3. SOCIAL SECTION */}
|
||||
<View style={styles.sectionContainer}>
|
||||
<View style={[styles.sectionHeader, { borderLeftColor: '#2196F3' }]}>
|
||||
<Text style={styles.sectionTitle}>SOCIAL 💬</Text>
|
||||
</View>
|
||||
<View style={styles.appsGrid}>
|
||||
{renderAppIcon('whatsKURD', '💬', () => navigation.navigate('WhatsKURD'), true, true)}
|
||||
{renderAppIcon('Forum', qaForum, () => navigation.navigate('Forum'), false)}
|
||||
{renderAppIcon('KurdMedia', qaKurdMedia, () => navigation.navigate('KurdMedia'), false)}
|
||||
{renderAppIcon('Events', '🎭', () => navigation.navigate('Events'), true, true)}
|
||||
{renderAppIcon('Help', '🤝', () => navigation.navigate('Help'), true, true)}
|
||||
{renderAppIcon('Music', '🎵', () => navigation.navigate('Music'), true, true)}
|
||||
{renderAppIcon('VPN', '🛡️', () => navigation.navigate('VPN'), true, true)}
|
||||
{renderAppIcon('Referral', '👥', () => navigation.navigate('Referral'), true)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 4. EDUCATION SECTION */}
|
||||
<View style={styles.sectionContainer}>
|
||||
<View style={[styles.sectionHeader, { borderLeftColor: KurdistanColors.zer }]}>
|
||||
<Text style={styles.sectionTitle}>EDUCATION 📚</Text>
|
||||
</View>
|
||||
<View style={styles.appsGrid}>
|
||||
{renderAppIcon('University', qaUniversity, () => navigation.navigate('University'), false, true)}
|
||||
{renderAppIcon('Perwerde', qaEducation, () => navigation.navigate('Perwerde'), false)}
|
||||
{renderAppIcon('Certificates', '🏆', () => navigation.navigate('Certificates'), true, true)}
|
||||
{renderAppIcon('Research', '🔬', () => navigation.navigate('Research'), true, true)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={{ height: 100 }} />
|
||||
</ScrollView>
|
||||
|
||||
{/* Avatar Picker Modal */}
|
||||
<AvatarPickerModal
|
||||
visible={avatarModalVisible}
|
||||
onClose={() => setAvatarModalVisible(false)}
|
||||
currentAvatar={profileData?.avatar_url ?? undefined}
|
||||
onAvatarSelected={handleAvatarSelected}
|
||||
/>
|
||||
|
||||
{/* Notification Center Modal */}
|
||||
<NotificationCenterModal
|
||||
visible={notificationModalVisible}
|
||||
onClose={() => setNotificationModalVisible(false)}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#F2F2F7',
|
||||
},
|
||||
scrollView: {
|
||||
flex: 1,
|
||||
},
|
||||
scrollContent: {
|
||||
paddingBottom: 40,
|
||||
},
|
||||
header: {
|
||||
paddingTop: Platform.OS === 'android' ? 40 : 20,
|
||||
paddingBottom: 25,
|
||||
paddingHorizontal: 20,
|
||||
borderBottomLeftRadius: 24,
|
||||
borderBottomRightRadius: 24,
|
||||
boxShadow: '0px 4px 8px rgba(0, 0, 0, 0.2)',
|
||||
elevation: 8,
|
||||
},
|
||||
headerTop: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
avatarSection: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
avatar: {
|
||||
width: 56,
|
||||
height: 56,
|
||||
borderRadius: 28,
|
||||
borderWidth: 2,
|
||||
borderColor: KurdistanColors.spi,
|
||||
backgroundColor: '#ddd',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
avatarEmoji: {
|
||||
fontSize: 32,
|
||||
},
|
||||
tikiAvatarBadge: {
|
||||
marginLeft: 8,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.25)',
|
||||
paddingHorizontal: 10,
|
||||
paddingVertical: 4,
|
||||
borderRadius: 12,
|
||||
borderWidth: 1,
|
||||
borderColor: 'rgba(255, 255, 255, 0.4)',
|
||||
},
|
||||
tikiAvatarText: {
|
||||
fontSize: 11,
|
||||
color: KurdistanColors.spi,
|
||||
fontWeight: '700',
|
||||
},
|
||||
statusIndicator: {
|
||||
position: 'absolute',
|
||||
bottom: 2,
|
||||
right: 2,
|
||||
width: 14,
|
||||
height: 14,
|
||||
borderRadius: 7,
|
||||
backgroundColor: '#4CAF50', // Online green
|
||||
borderWidth: 2,
|
||||
borderColor: KurdistanColors.kesk,
|
||||
},
|
||||
headerInfo: {
|
||||
flex: 1,
|
||||
marginLeft: 16,
|
||||
},
|
||||
greeting: {
|
||||
fontSize: 20,
|
||||
fontWeight: 'bold',
|
||||
color: KurdistanColors.spi,
|
||||
marginBottom: 4,
|
||||
},
|
||||
tikiContainer: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
},
|
||||
tikiBadge: {
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.2)',
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 2,
|
||||
borderRadius: 12,
|
||||
marginRight: 6,
|
||||
marginBottom: 4,
|
||||
},
|
||||
tikiText: {
|
||||
fontSize: 11,
|
||||
color: KurdistanColors.spi,
|
||||
fontWeight: '600',
|
||||
},
|
||||
headerActions: {
|
||||
flexDirection: 'row',
|
||||
},
|
||||
iconButton: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.15)',
|
||||
borderRadius: 20,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginLeft: 8,
|
||||
},
|
||||
headerIcon: {
|
||||
fontSize: 18,
|
||||
},
|
||||
sectionContainer: {
|
||||
backgroundColor: KurdistanColors.spi,
|
||||
marginHorizontal: 16,
|
||||
marginTop: 16,
|
||||
borderRadius: 16,
|
||||
padding: 16,
|
||||
boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.05)',
|
||||
elevation: 2,
|
||||
},
|
||||
sectionHeader: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 16,
|
||||
borderLeftWidth: 4,
|
||||
paddingLeft: 10,
|
||||
},
|
||||
sectionTitleRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 10,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: '800',
|
||||
color: KurdistanColors.reş,
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
connectWalletBadge: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: KurdistanColors.kesk,
|
||||
paddingHorizontal: 10,
|
||||
paddingVertical: 4,
|
||||
borderRadius: 12,
|
||||
gap: 4,
|
||||
},
|
||||
connectWalletIcon: {
|
||||
fontSize: 14,
|
||||
},
|
||||
connectWalletText: {
|
||||
fontSize: 11,
|
||||
fontWeight: '600',
|
||||
color: KurdistanColors.spi,
|
||||
},
|
||||
seeAllText: {
|
||||
fontSize: 12,
|
||||
color: KurdistanColors.kesk,
|
||||
fontWeight: '600',
|
||||
},
|
||||
appsGrid: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'flex-start',
|
||||
},
|
||||
appIconContainer: {
|
||||
width: '25%', // 4 icons per row
|
||||
alignItems: 'center',
|
||||
marginBottom: 16,
|
||||
},
|
||||
appIconBox: {
|
||||
width: 56,
|
||||
height: 56,
|
||||
borderRadius: 16,
|
||||
backgroundColor: '#F8F9FA',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginBottom: 6,
|
||||
boxShadow: '0px 1px 2px rgba(0, 0, 0, 0.05)',
|
||||
elevation: 1,
|
||||
},
|
||||
appIconDisabled: {
|
||||
opacity: 0.5,
|
||||
backgroundColor: '#F0F0F0',
|
||||
},
|
||||
imageIcon: {
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: 8,
|
||||
},
|
||||
emojiIcon: {
|
||||
fontSize: 28,
|
||||
},
|
||||
appIconTitle: {
|
||||
fontSize: 11,
|
||||
color: '#333',
|
||||
textAlign: 'center',
|
||||
fontWeight: '500',
|
||||
maxWidth: '90%',
|
||||
},
|
||||
lockBadge: {
|
||||
position: 'absolute',
|
||||
top: -4,
|
||||
right: -4,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
lockText: {
|
||||
fontSize: 12,
|
||||
},
|
||||
// Score Cards Styles
|
||||
scoreCardsContainer: {
|
||||
marginTop: 16,
|
||||
marginBottom: 8,
|
||||
},
|
||||
scoreCardsContent: {
|
||||
paddingHorizontal: 16,
|
||||
},
|
||||
scoreCard: {
|
||||
backgroundColor: KurdistanColors.spi,
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
marginRight: 12,
|
||||
minWidth: 140,
|
||||
borderLeftWidth: 4,
|
||||
boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.08)',
|
||||
elevation: 3,
|
||||
},
|
||||
scoreCardIcon: {
|
||||
fontSize: 28,
|
||||
marginBottom: 8,
|
||||
},
|
||||
scoreCardLabel: {
|
||||
fontSize: 11,
|
||||
color: '#666',
|
||||
fontWeight: '600',
|
||||
marginBottom: 6,
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
scoreCardValue: {
|
||||
fontSize: 24,
|
||||
fontWeight: 'bold',
|
||||
color: KurdistanColors.reş,
|
||||
marginBottom: 4,
|
||||
},
|
||||
scoreCardSubtext: {
|
||||
fontSize: 10,
|
||||
color: '#999',
|
||||
},
|
||||
kycButton: {
|
||||
marginTop: 8,
|
||||
backgroundColor: KurdistanColors.kesk,
|
||||
paddingVertical: 6,
|
||||
paddingHorizontal: 12,
|
||||
borderRadius: 8,
|
||||
alignItems: 'center',
|
||||
},
|
||||
kycButtonText: {
|
||||
color: KurdistanColors.spi,
|
||||
fontSize: 11,
|
||||
fontWeight: '700',
|
||||
},
|
||||
});
|
||||
|
||||
export default DashboardScreen;
|
||||
Reference in New Issue
Block a user