mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-06-16 01:41:02 +00:00
Fix all ESLint errors in mobile app (157 errors -> 0)
Major fixes: - Replace `any` types with proper TypeScript types across all files - Convert require() imports to ES module imports - Add __DEV__ guards to console statements - Escape special characters in JSX (' and ") - Fix unused variables (prefix with _ or remove) - Fix React hooks violations (useCallback, useMemo patterns) - Convert wasm-crypto-shim.js to TypeScript - Add eslint-disable comments for valid setState patterns Files affected: 50+ screens, components, contexts, and services Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -71,7 +71,7 @@ const CATEGORIES: { name: CategoryType; icon: string }[] = [
|
||||
];
|
||||
|
||||
const AppsScreen: React.FC = () => {
|
||||
const navigation = useNavigation<any>();
|
||||
const navigation = useNavigation<{ navigate: (screen: string) => void }>();
|
||||
const { selectedAccount, accounts, connectWallet } = usePezkuwi();
|
||||
const isConnected = !!selectedAccount;
|
||||
|
||||
@@ -385,7 +385,7 @@ const AppsScreen: React.FC = () => {
|
||||
<View style={styles.infoTextContainer}>
|
||||
<Text style={styles.infoTitle}>Review Process</Text>
|
||||
<Text style={styles.infoText}>
|
||||
Your submission will be reviewed by Dijital Kurdistan Tech Inst. We'll contact you within 5-7 business days.
|
||||
Your submission will be reviewed by Dijital Kurdistan Tech Inst. We'll contact you within 5-7 business days.
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
} from 'react-native';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { useAuth } from '../contexts/AuthContext';
|
||||
import { KurdistanColors } from '../theme/colors';
|
||||
import kurdistanMapImage from '../../assets/kurdistan-map.png';
|
||||
|
||||
const AuthScreen: React.FC = () => {
|
||||
const { signIn, signUp } = useAuth();
|
||||
@@ -135,7 +135,7 @@ const AuthScreen: React.FC = () => {
|
||||
<View style={styles.header}>
|
||||
<View style={styles.logoContainer}>
|
||||
<Image
|
||||
source={require('../../assets/kurdistan-map.png')}
|
||||
source={kurdistanMapImage}
|
||||
style={styles.logoImage}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
|
||||
@@ -9,10 +9,8 @@ import {
|
||||
StatusBar,
|
||||
TextInput,
|
||||
Alert,
|
||||
ActivityIndicator,
|
||||
Modal,
|
||||
FlatList,
|
||||
Image,
|
||||
RefreshControl,
|
||||
} from 'react-native';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
@@ -191,7 +189,7 @@ const MOCK_LISTINGS: Listing[] = [
|
||||
];
|
||||
|
||||
const B2BScreen: React.FC = () => {
|
||||
const navigation = useNavigation();
|
||||
const _navigation = useNavigation();
|
||||
const { selectedAccount, api, getKeyPair } = usePezkuwi();
|
||||
|
||||
// State
|
||||
@@ -347,7 +345,7 @@ const B2BScreen: React.FC = () => {
|
||||
'Escrow hate damezrandin!\nEscrow has been created!\n\nDrav di ewlehiyê de ye.\nFunds are secured.',
|
||||
[{ text: 'Temam / OK' }]
|
||||
);
|
||||
} catch (error) {
|
||||
} catch {
|
||||
Alert.alert('Şaşî / Error', 'Escrow nehat damezrandin / Escrow failed');
|
||||
}
|
||||
},
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
Dimensions,
|
||||
Platform,
|
||||
ActivityIndicator,
|
||||
ImageSourcePropType,
|
||||
} from 'react-native';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
@@ -24,7 +25,7 @@ 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, getTikiColor } from '../../shared/lib/tiki';
|
||||
import { fetchUserTikis, getPrimaryRole, getTikiDisplayName, getTikiEmoji } from '../../shared/lib/tiki';
|
||||
import { getAllScores, type UserScores } from '../../shared/lib/scores';
|
||||
import { getKycStatus } from '../../shared/lib/kyc';
|
||||
|
||||
@@ -36,12 +37,12 @@ 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 _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
|
||||
|
||||
const { width } = Dimensions.get('window');
|
||||
const { width: _width } = Dimensions.get('window');
|
||||
|
||||
// Avatar pool matching AvatarPickerModal
|
||||
const AVATAR_POOL = [
|
||||
@@ -79,14 +80,21 @@ const getEmojiFromAvatarId = (avatarId: string): string => {
|
||||
return avatar ? avatar.emoji : '👤'; // Default to person emoji if not found
|
||||
};
|
||||
|
||||
interface DashboardScreenProps {}
|
||||
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<any>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [profileData, setProfileData] = useState<ProfileData | null>(null);
|
||||
const [_loading, setLoading] = useState(true);
|
||||
const [avatarModalVisible, setAvatarModalVisible] = useState(false);
|
||||
const [notificationModalVisible, setNotificationModalVisible] = useState(false);
|
||||
|
||||
@@ -166,7 +174,7 @@ const DashboardScreen: React.FC<DashboardScreenProps> = () => {
|
||||
}, [fetchBlockchainData]);
|
||||
|
||||
// Check if user is a visitor (default when no blockchain wallet or no tikis)
|
||||
const isVisitor = !selectedAccount || tikis.length === 0;
|
||||
const _isVisitor = !selectedAccount || tikis.length === 0;
|
||||
|
||||
// Handle wallet connection
|
||||
const handleConnectWallet = async () => {
|
||||
@@ -184,7 +192,7 @@ const DashboardScreen: React.FC<DashboardScreenProps> = () => {
|
||||
};
|
||||
const primaryRole = tikis.length > 0 ? getPrimaryRole(tikis) : 'Visitor';
|
||||
|
||||
const showComingSoon = (featureName: string) => {
|
||||
const _showComingSoon = (featureName: string) => {
|
||||
Alert.alert(
|
||||
'Coming Soon',
|
||||
`${featureName} will be available soon!`,
|
||||
@@ -192,7 +200,7 @@ const DashboardScreen: React.FC<DashboardScreenProps> = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const showAwaitingGovernment = () => {
|
||||
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.',
|
||||
@@ -200,7 +208,7 @@ const DashboardScreen: React.FC<DashboardScreenProps> = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const showUnderMaintenance = () => {
|
||||
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.',
|
||||
@@ -208,7 +216,7 @@ const DashboardScreen: React.FC<DashboardScreenProps> = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const showAwaitingSerokElection = () => {
|
||||
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.',
|
||||
@@ -216,7 +224,7 @@ const DashboardScreen: React.FC<DashboardScreenProps> = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const showAwaitingMinistryOfEducation = () => {
|
||||
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.',
|
||||
@@ -230,13 +238,13 @@ const DashboardScreen: React.FC<DashboardScreenProps> = () => {
|
||||
|
||||
const handleAvatarSelected = (avatarUrl: string) => {
|
||||
// Refresh profile data to show new avatar
|
||||
setProfileData((prev: any) => ({
|
||||
setProfileData((prev: ProfileData | null) => ({
|
||||
...prev,
|
||||
avatar_url: avatarUrl,
|
||||
}));
|
||||
};
|
||||
|
||||
const renderAppIcon = (title: string, icon: any, onPress: () => void, isEmoji = false, comingSoon = false) => (
|
||||
const renderAppIcon = (title: string, icon: string | ImageSourcePropType, onPress: () => void, isEmoji = false, comingSoon = false) => (
|
||||
<TouchableOpacity
|
||||
style={styles.appIconContainer}
|
||||
onPress={onPress}
|
||||
@@ -556,7 +564,7 @@ const DashboardScreen: React.FC<DashboardScreenProps> = () => {
|
||||
<AvatarPickerModal
|
||||
visible={avatarModalVisible}
|
||||
onClose={() => setAvatarModalVisible(false)}
|
||||
currentAvatar={profileData?.avatar_url}
|
||||
currentAvatar={profileData?.avatar_url ?? undefined}
|
||||
onAvatarSelected={handleAvatarSelected}
|
||||
/>
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
Alert,
|
||||
Platform,
|
||||
KeyboardAvoidingView,
|
||||
AlertButton,
|
||||
} from 'react-native';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { useAuth } from '../contexts/AuthContext';
|
||||
@@ -20,7 +21,7 @@ import { supabase } from '../lib/supabase';
|
||||
import AvatarPickerModal from '../components/AvatarPickerModal';
|
||||
|
||||
// Cross-platform alert helper
|
||||
const showAlert = (title: string, message: string, buttons?: Array<{text: string; onPress?: () => void; style?: string}>) => {
|
||||
const showAlert = (title: string, message: string, buttons?: AlertButton[]) => {
|
||||
if (Platform.OS === 'web') {
|
||||
if (buttons && buttons.length > 1) {
|
||||
const result = window.confirm(`${title}\n\n${message}`);
|
||||
@@ -34,7 +35,7 @@ const showAlert = (title: string, message: string, buttons?: Array<{text: string
|
||||
if (buttons?.[0]?.onPress) buttons[0].onPress();
|
||||
}
|
||||
} else {
|
||||
Alert.alert(title, message, buttons as any);
|
||||
Alert.alert(title, message, buttons);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -76,7 +77,7 @@ const getEmojiFromAvatarId = (avatarId: string): string => {
|
||||
const EditProfileScreen: React.FC = () => {
|
||||
const navigation = useNavigation();
|
||||
const { user } = useAuth();
|
||||
const { isDarkMode, colors, fontScale } = useTheme();
|
||||
const { isDarkMode: _isDarkMode, colors, fontScale } = useTheme();
|
||||
|
||||
const [fullName, setFullName] = useState('');
|
||||
const [avatarUrl, setAvatarUrl] = useState<string | null>(null);
|
||||
|
||||
@@ -17,8 +17,6 @@ import { usePezkuwi } from '../contexts/PezkuwiContext';
|
||||
import {
|
||||
fetchUserTikiNFTs,
|
||||
getCitizenNFTDetails,
|
||||
getTikiDisplayName,
|
||||
getTikiEmoji,
|
||||
ROLE_CATEGORIES,
|
||||
type TikiNFTDetails,
|
||||
} from '../../shared/lib/tiki';
|
||||
@@ -223,7 +221,7 @@ const IdentityScreen: React.FC = () => {
|
||||
<Text style={styles.notCitizenIcon}>⚠️</Text>
|
||||
<Text style={styles.notCitizenTitle}>Citizenship Not Found</Text>
|
||||
<Text style={styles.notCitizenText}>
|
||||
We couldn't find a Welati (citizen) NFT for this wallet.
|
||||
We couldn't find a Welati (citizen) NFT for this wallet.
|
||||
Please apply for citizenship to get your digital identity.
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
|
||||
@@ -9,9 +9,7 @@ import {
|
||||
StatusBar,
|
||||
Alert,
|
||||
Linking,
|
||||
Image,
|
||||
} from 'react-native';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { KurdistanColors } from '../theme/colors';
|
||||
|
||||
@@ -140,7 +138,7 @@ const SOCIAL_PLATFORMS: SocialPlatform[] = [
|
||||
];
|
||||
|
||||
const KurdMediaScreen: React.FC = () => {
|
||||
const navigation = useNavigation();
|
||||
const _navigation = useNavigation();
|
||||
|
||||
const handleMediaPress = (channel: MediaChannel) => {
|
||||
Alert.alert(
|
||||
@@ -162,7 +160,7 @@ const KurdMediaScreen: React.FC = () => {
|
||||
[{ text: 'Temam / OK' }]
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
} catch {
|
||||
Alert.alert('Xeletî / Error', 'Tiştek xelet çû.\nSomething went wrong.');
|
||||
}
|
||||
};
|
||||
@@ -284,7 +282,7 @@ const KurdMediaScreen: React.FC = () => {
|
||||
<Text style={styles.infoBannerIcon}>💡</Text>
|
||||
<View style={styles.infoBannerContent}>
|
||||
<Text style={styles.infoBannerText}>
|
||||
PezkuwiChain - Blockchain'a yekem a netewî ya Kurdan
|
||||
PezkuwiChain - Blockchain'a yekem a netewî ya Kurdan
|
||||
</Text>
|
||||
<Text style={styles.infoBannerTextEn}>
|
||||
PezkuwiChain - The first national blockchain of the Kurds
|
||||
|
||||
@@ -64,11 +64,40 @@ interface ContributionInfo {
|
||||
refunded: boolean;
|
||||
}
|
||||
|
||||
// Raw presale data from chain toJSON()
|
||||
interface PresaleChainData {
|
||||
owner?: string;
|
||||
paymentAsset?: number;
|
||||
rewardAsset?: number;
|
||||
tokensForSale?: string | number;
|
||||
startBlock?: number;
|
||||
duration?: number;
|
||||
status?: PresaleStatus;
|
||||
accessControl?: 'Public' | 'Whitelist';
|
||||
limits?: {
|
||||
minContribution?: string | number;
|
||||
maxContribution?: string | number;
|
||||
softCap?: string | number;
|
||||
hardCap?: string | number;
|
||||
};
|
||||
vesting?: VestingSchedule | null;
|
||||
gracePeriodBlocks?: number;
|
||||
refundFeePercent?: number;
|
||||
graceRefundFeePercent?: number;
|
||||
}
|
||||
|
||||
// Raw contribution data from chain toJSON()
|
||||
interface ContributionChainData {
|
||||
amount?: string | number;
|
||||
contributedAt?: number;
|
||||
refunded?: boolean;
|
||||
}
|
||||
|
||||
const BLOCK_TIME_SECONDS = 6;
|
||||
const PLATFORM_FEE_PERCENT = 2;
|
||||
|
||||
const LaunchpadScreen: React.FC = () => {
|
||||
const navigation = useNavigation();
|
||||
const _navigation = useNavigation();
|
||||
const { api, selectedAccount, isApiReady, getKeyPair } = usePezkuwi();
|
||||
|
||||
const [presales, setPresales] = useState<PresaleConfig[]>([]);
|
||||
@@ -80,7 +109,7 @@ const LaunchpadScreen: React.FC = () => {
|
||||
const [userContributions, setUserContributions] = useState<Record<number, ContributionInfo>>({});
|
||||
const [assetBalances, setAssetBalances] = useState<Record<number, string>>({});
|
||||
const [showDetailModal, setShowDetailModal] = useState(false);
|
||||
const [currentBlock, setCurrentBlock] = useState(0);
|
||||
const [_currentBlock, setCurrentBlock] = useState(0);
|
||||
|
||||
// Fetch all presales from chain
|
||||
const fetchPresales = useCallback(async () => {
|
||||
@@ -113,7 +142,7 @@ const LaunchpadScreen: React.FC = () => {
|
||||
const presaleData = await api.query.presale?.presales?.(id);
|
||||
if (!presaleData || presaleData.isNone) continue;
|
||||
|
||||
const config = presaleData.toJSON() as any;
|
||||
const config = presaleData.toJSON() as unknown as PresaleChainData;
|
||||
if (!config) continue;
|
||||
|
||||
// Get total raised and contributors
|
||||
@@ -124,7 +153,8 @@ const LaunchpadScreen: React.FC = () => {
|
||||
const duration = config.duration || 0;
|
||||
const endBlock = startBlock + duration;
|
||||
const totalRaisedStr = totalRaised?.toString() || '0';
|
||||
const hardCap = config.limits?.hardCap || '0';
|
||||
const hardCapValue = config.limits?.hardCap;
|
||||
const hardCap = hardCapValue !== undefined ? String(hardCapValue) : '0';
|
||||
|
||||
// Calculate progress
|
||||
const progress = hardCap !== '0'
|
||||
@@ -177,7 +207,7 @@ const LaunchpadScreen: React.FC = () => {
|
||||
// Get user's contribution for this presale
|
||||
const contribution = await api.query.presale?.contributions?.(presale.id, selectedAccount.address);
|
||||
if (contribution && !contribution.isNone) {
|
||||
const contribData = contribution.toJSON() as any;
|
||||
const contribData = contribution.toJSON() as unknown as ContributionChainData;
|
||||
userContribs[presale.id] = {
|
||||
amount: contribData?.amount?.toString() || '0',
|
||||
contributedAt: contribData?.contributedAt || 0,
|
||||
@@ -360,8 +390,9 @@ const LaunchpadScreen: React.FC = () => {
|
||||
setContributionAmount('');
|
||||
setShowDetailModal(false);
|
||||
fetchPresales();
|
||||
} catch (error: any) {
|
||||
Alert.alert('Çewtî', error.message || 'Contribution failed.');
|
||||
} catch (error: unknown) {
|
||||
const message = error instanceof Error ? error.message : 'Contribution failed.';
|
||||
Alert.alert('Çewtî', message);
|
||||
} finally {
|
||||
setContributing(false);
|
||||
}
|
||||
@@ -413,8 +444,9 @@ const LaunchpadScreen: React.FC = () => {
|
||||
|
||||
Alert.alert('Serketî!', 'Refund processed successfully!');
|
||||
fetchPresales();
|
||||
} catch (error: any) {
|
||||
Alert.alert('Çewtî', error.message || 'Refund failed.');
|
||||
} catch (error: unknown) {
|
||||
const message = error instanceof Error ? error.message : 'Refund failed.';
|
||||
Alert.alert('Çewtî', message);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -31,7 +31,7 @@ const P2PPlatformScreen: React.FC = () => {
|
||||
const [selectedTab, setSelectedTab] = useState<'buy' | 'sell'>('buy');
|
||||
const [selectedFilter, setSelectedFilter] = useState<'all' | 'bank' | 'online'>('all');
|
||||
const [ads, setAds] = useState<P2PAd[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [_loading, setLoading] = useState(false);
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
|
||||
const fetchAds = async () => {
|
||||
|
||||
@@ -37,10 +37,30 @@ interface Enrollment {
|
||||
points_earned: number;
|
||||
}
|
||||
|
||||
// Raw course data from chain toJSON()
|
||||
interface CourseChainData {
|
||||
id: number;
|
||||
owner: string;
|
||||
name: number[] | string;
|
||||
description: number[] | string;
|
||||
contentLink: number[] | string;
|
||||
status: 'Active' | 'Archived';
|
||||
createdAt: number;
|
||||
}
|
||||
|
||||
// Raw enrollment data from chain toJSON()
|
||||
interface EnrollmentChainData {
|
||||
student: string;
|
||||
courseId: number;
|
||||
enrolledAt: number;
|
||||
completedAt: number | null;
|
||||
pointsEarned: number;
|
||||
}
|
||||
|
||||
type TabType = 'courses' | 'enrolled' | 'completed';
|
||||
|
||||
const PerwerdeScreen: React.FC = () => {
|
||||
const navigation = useNavigation();
|
||||
const _navigation = useNavigation();
|
||||
const { selectedAccount, api, isApiReady } = usePezkuwi();
|
||||
const isConnected = !!selectedAccount;
|
||||
|
||||
@@ -63,9 +83,9 @@ const PerwerdeScreen: React.FC = () => {
|
||||
const entries = await api.query.perwerde.courses.entries();
|
||||
const courseList: Course[] = [];
|
||||
|
||||
for (const [key, value] of entries) {
|
||||
for (const [_key, value] of entries) {
|
||||
if (!value.isEmpty) {
|
||||
const data = value.toJSON() as any;
|
||||
const data = value.toJSON() as unknown as CourseChainData;
|
||||
courseList.push({
|
||||
id: data.id,
|
||||
owner: data.owner,
|
||||
@@ -100,7 +120,7 @@ const PerwerdeScreen: React.FC = () => {
|
||||
for (const courseId of courseIds) {
|
||||
const enrollment = await api.query.perwerde.enrollments([selectedAccount.address, courseId]);
|
||||
if (!enrollment.isEmpty) {
|
||||
const data = enrollment.toJSON() as any;
|
||||
const data = enrollment.toJSON() as unknown as EnrollmentChainData;
|
||||
enrollmentList.push({
|
||||
student: data.student,
|
||||
course_id: data.courseId,
|
||||
@@ -236,7 +256,7 @@ const PerwerdeScreen: React.FC = () => {
|
||||
} else {
|
||||
Alert.alert('Xeletî / Error', 'Nikarim linkê vebikum.');
|
||||
}
|
||||
} catch (error) {
|
||||
} catch {
|
||||
Alert.alert('Xeletî / Error', 'Tiştek xelet çû.');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -14,6 +14,28 @@ import {
|
||||
import { KurdistanColors } from '../theme/colors';
|
||||
import { usePezkuwi } from '../contexts/PezkuwiContext';
|
||||
|
||||
// Types for Polkadot API responses
|
||||
interface PoolKeyData {
|
||||
0?: string[];
|
||||
[key: number]: string[] | undefined;
|
||||
}
|
||||
|
||||
interface AssetMetadata {
|
||||
symbol?: string;
|
||||
decimals?: number;
|
||||
}
|
||||
|
||||
interface AccountInfo {
|
||||
data: {
|
||||
free: { toString(): string };
|
||||
};
|
||||
}
|
||||
|
||||
interface AssetAccount {
|
||||
isSome: boolean;
|
||||
unwrap(): { balance: { toString(): string } };
|
||||
}
|
||||
|
||||
interface PoolInfo {
|
||||
id: string;
|
||||
asset1: number;
|
||||
@@ -52,7 +74,7 @@ const PoolBrowserScreen: React.FC = () => {
|
||||
const poolAccount = value.toString();
|
||||
|
||||
// Parse pool assets from key
|
||||
const keyData = key.toHuman() as any;
|
||||
const keyData = key.toHuman() as unknown as PoolKeyData;
|
||||
const assets = keyData[0];
|
||||
|
||||
if (!assets || assets.length !== 2) continue;
|
||||
@@ -69,14 +91,14 @@ const PoolBrowserScreen: React.FC = () => {
|
||||
try {
|
||||
if (asset1 !== 0) {
|
||||
const metadata1 = await api.query.assets.metadata(asset1);
|
||||
const meta1 = metadata1.toJSON() as any;
|
||||
const meta1 = metadata1.toJSON() as unknown as AssetMetadata;
|
||||
asset1Symbol = meta1.symbol || `Asset ${asset1}`;
|
||||
asset1Decimals = meta1.decimals || 12;
|
||||
}
|
||||
|
||||
if (asset2 !== 0) {
|
||||
const metadata2 = await api.query.assets.metadata(asset2);
|
||||
const meta2 = metadata2.toJSON() as any;
|
||||
const meta2 = metadata2.toJSON() as unknown as AssetMetadata;
|
||||
asset2Symbol = meta2.symbol || `Asset ${asset2}`;
|
||||
asset2Decimals = meta2.decimals || 12;
|
||||
}
|
||||
@@ -91,18 +113,18 @@ const PoolBrowserScreen: React.FC = () => {
|
||||
try {
|
||||
if (asset1 === 0) {
|
||||
// Native token (wHEZ)
|
||||
const balance1 = await api.query.system.account(poolAccount) as any;
|
||||
const balance1 = await api.query.system.account(poolAccount) as unknown as AccountInfo;
|
||||
reserve1 = balance1.data.free.toString();
|
||||
} else {
|
||||
const balance1 = await api.query.assets.account(asset1, poolAccount) as any;
|
||||
const balance1 = await api.query.assets.account(asset1, poolAccount) as unknown as AssetAccount;
|
||||
reserve1 = balance1.isSome ? balance1.unwrap().balance.toString() : '0';
|
||||
}
|
||||
|
||||
if (asset2 === 0) {
|
||||
const balance2 = await api.query.system.account(poolAccount) as any;
|
||||
const balance2 = await api.query.system.account(poolAccount) as unknown as AccountInfo;
|
||||
reserve2 = balance2.data.free.toString();
|
||||
} else {
|
||||
const balance2 = await api.query.assets.account(asset2, poolAccount) as any;
|
||||
const balance2 = await api.query.assets.account(asset2, poolAccount) as unknown as AssetAccount;
|
||||
reserve2 = balance2.isSome ? balance2.unwrap().balance.toString() : '0';
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
StatusBar,
|
||||
ActivityIndicator,
|
||||
Alert,
|
||||
FlatList,
|
||||
Modal,
|
||||
RefreshControl,
|
||||
} from 'react-native';
|
||||
@@ -256,9 +255,10 @@ const PresidentScreen: React.FC = () => {
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
if (__DEV__) console.error('[President] Vote error:', error);
|
||||
Alert.alert('Error', error.message || 'Failed to submit vote');
|
||||
const errorMessage = error instanceof Error ? error.message : 'Failed to submit vote';
|
||||
Alert.alert('Error', errorMessage);
|
||||
setSubmittingVote(false);
|
||||
}
|
||||
};
|
||||
@@ -425,7 +425,7 @@ const PresidentScreen: React.FC = () => {
|
||||
</Text>
|
||||
</View>
|
||||
) : (
|
||||
pastElections.map((result, index) => (
|
||||
pastElections.map((result, _index) => (
|
||||
<View key={result.electionId} style={styles.historyCard}>
|
||||
<View style={styles.historyHeader}>
|
||||
<Text style={styles.historyTitle}>Election #{result.electionId}</Text>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
|
||||
@@ -22,8 +22,6 @@ import { KurdistanColors } from '../theme/colors';
|
||||
import {
|
||||
getReferralStats,
|
||||
getMyReferrals,
|
||||
calculateReferralScore,
|
||||
type ReferralStats as BlockchainReferralStats,
|
||||
} from '../../shared/lib/referral';
|
||||
|
||||
// Share platform types
|
||||
@@ -93,7 +91,7 @@ const ReferralScreen: React.FC = () => {
|
||||
: '';
|
||||
|
||||
// Deep link for app-to-app sharing
|
||||
const deepLink = selectedAccount
|
||||
const _deepLink = selectedAccount
|
||||
? `pezkuwichain://join?ref=${selectedAccount.address}`
|
||||
: '';
|
||||
|
||||
@@ -181,7 +179,7 @@ const ReferralScreen: React.FC = () => {
|
||||
if (!selectedAccount) return;
|
||||
|
||||
const encodedMessage = encodeURIComponent(shareMessage);
|
||||
const encodedLink = encodeURIComponent(referralLink);
|
||||
const _encodedLink = encodeURIComponent(referralLink);
|
||||
|
||||
let url = '';
|
||||
|
||||
@@ -624,7 +622,7 @@ const ReferralScreen: React.FC = () => {
|
||||
|
||||
<Text style={styles.qrInstructions}>
|
||||
Bu QR kodu arkadaşlarınla paylaş.{'\n'}
|
||||
Taratarak Pezkuwi'ye katılabilirler.
|
||||
Taratarak Pezkuwi'ye katılabilirler.
|
||||
</Text>
|
||||
<Text style={styles.qrInstructionsEn}>
|
||||
Share this QR code with friends.{'\n'}
|
||||
|
||||
@@ -19,8 +19,20 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import * as SecureStore from 'expo-secure-store';
|
||||
import { Clipboard } from 'react-native';
|
||||
import { useNavigation, NavigationProp } from '@react-navigation/native';
|
||||
import type { AlertButton } from 'react-native';
|
||||
import { RootStackParamList } from '../navigation/AppNavigator';
|
||||
import { KurdistanColors } from '../theme/colors';
|
||||
|
||||
// Profile type for Supabase
|
||||
interface UserProfile {
|
||||
id?: string;
|
||||
full_name: string;
|
||||
username: string;
|
||||
bio?: string;
|
||||
notifications_push: boolean;
|
||||
notifications_email: boolean;
|
||||
updated_at?: string;
|
||||
}
|
||||
import { useTheme } from '../contexts/ThemeContext';
|
||||
import { useBiometricAuth } from '../contexts/BiometricAuthContext';
|
||||
import { useAuth } from '../contexts/AuthContext';
|
||||
@@ -28,7 +40,7 @@ import { usePezkuwi, NETWORKS } from '../contexts/PezkuwiContext';
|
||||
import { supabase } from '../lib/supabase';
|
||||
|
||||
// Cross-platform alert helper
|
||||
const showAlert = (title: string, message: string, buttons?: Array<{text: string; onPress?: () => void; style?: string}>) => {
|
||||
const showAlert = (title: string, message: string, buttons?: AlertButton[]) => {
|
||||
if (Platform.OS === 'web') {
|
||||
if (buttons && buttons.length > 1) {
|
||||
// For confirm dialogs
|
||||
@@ -40,7 +52,7 @@ const showAlert = (title: string, message: string, buttons?: Array<{text: string
|
||||
window.alert(`${title}\n\n${message}`);
|
||||
}
|
||||
} else {
|
||||
Alert.alert(title, message, buttons as any);
|
||||
Alert.alert(title, message, buttons);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -160,13 +172,13 @@ const SettingsScreen: React.FC = () => {
|
||||
const { currentNetwork, switchNetwork, selectedAccount } = usePezkuwi();
|
||||
|
||||
// Profile State (Supabase)
|
||||
const [profile, setProfile] = useState<any>({
|
||||
const [profile, setProfile] = useState<UserProfile>({
|
||||
full_name: '',
|
||||
username: '',
|
||||
notifications_push: false,
|
||||
notifications_email: true,
|
||||
});
|
||||
const [loadingProfile, setLoadingProfile] = useState(false);
|
||||
const [_loadingProfile, setLoadingProfile] = useState(false);
|
||||
const [savingSettings, setSavingSettings] = useState(false);
|
||||
|
||||
// Modals
|
||||
@@ -196,8 +208,8 @@ const SettingsScreen: React.FC = () => {
|
||||
setEditName(data.full_name || '');
|
||||
setEditBio(data.bio || '');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Error fetching profile:', err);
|
||||
} catch (_err) {
|
||||
console.log('Error fetching profile:', _err);
|
||||
} finally {
|
||||
setLoadingProfile(false);
|
||||
}
|
||||
@@ -211,9 +223,9 @@ const SettingsScreen: React.FC = () => {
|
||||
const updateSetting = async (key: string, value: boolean) => {
|
||||
if (!user) return;
|
||||
setSavingSettings(true);
|
||||
|
||||
|
||||
// Optimistic update
|
||||
setProfile((prev: any) => ({ ...prev, [key]: value }));
|
||||
setProfile((prev) => ({ ...prev, [key]: value }));
|
||||
|
||||
try {
|
||||
const { error } = await supabase
|
||||
@@ -225,7 +237,7 @@ const SettingsScreen: React.FC = () => {
|
||||
} catch (err) {
|
||||
console.error('Failed to update setting:', err);
|
||||
// Revert on error
|
||||
setProfile((prev: any) => ({ ...prev, [key]: !value }));
|
||||
setProfile((prev) => ({ ...prev, [key]: !value }));
|
||||
showAlert('Error', 'Failed to save setting. Please check your connection.');
|
||||
} finally {
|
||||
setSavingSettings(false);
|
||||
@@ -246,11 +258,11 @@ const SettingsScreen: React.FC = () => {
|
||||
.eq('id', user.id);
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
setProfile((prev: any) => ({ ...prev, full_name: editName, bio: editBio }));
|
||||
|
||||
setProfile((prev) => ({ ...prev, full_name: editName, bio: editBio }));
|
||||
setShowProfileEdit(false);
|
||||
showAlert('Success', 'Profile updated successfully');
|
||||
} catch (err) {
|
||||
} catch {
|
||||
showAlert('Error', 'Failed to update profile');
|
||||
}
|
||||
};
|
||||
@@ -502,7 +514,7 @@ const SettingsScreen: React.FC = () => {
|
||||
'@pezkuwi_selected_network'
|
||||
]);
|
||||
showAlert('Success', 'Wallet data cleared. Restart the app to see changes.');
|
||||
} catch (error) {
|
||||
} catch {
|
||||
showAlert('Error', 'Failed to clear wallet data');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,7 +297,7 @@ const WalletScreen: React.FC = () => {
|
||||
}
|
||||
|
||||
// Subscribe to balance changes
|
||||
unsubscribe = await api.query.system.account(accountId, (accountInfo: any) => {
|
||||
unsubscribe = await api.query.system.account(accountId, (accountInfo: { data: { free: { toString(): string } } }) => {
|
||||
const hezBalance = (Number(accountInfo.data.free.toString()) / 1e12).toFixed(2);
|
||||
setBalances(prev => ({ ...prev, HEZ: hezBalance }));
|
||||
if (__DEV__) console.warn('[Wallet] Balance updated via subscription:', hezBalance, 'HEZ');
|
||||
@@ -471,7 +471,7 @@ const WalletScreen: React.FC = () => {
|
||||
decodeAddress(address);
|
||||
setAddressError('');
|
||||
return true;
|
||||
} catch (e) {
|
||||
} catch {
|
||||
setAddressError('Invalid address format');
|
||||
return false;
|
||||
}
|
||||
@@ -570,7 +570,7 @@ const WalletScreen: React.FC = () => {
|
||||
throw new Error('Unknown token type');
|
||||
}
|
||||
|
||||
await tx.signAndSend(keypair, ({ status, events }) => {
|
||||
await tx.signAndSend(keypair, ({ status, _events }) => {
|
||||
if (status.isInBlock) {
|
||||
if (__DEV__) console.warn('[Wallet] Transaction in block:', status.asInBlock.toHex());
|
||||
}
|
||||
@@ -584,25 +584,25 @@ const WalletScreen: React.FC = () => {
|
||||
fetchData();
|
||||
}
|
||||
});
|
||||
} catch (e: any) {
|
||||
} catch (e: unknown) {
|
||||
setIsSending(false);
|
||||
showAlert('Error', e.message);
|
||||
showAlert('Error', (e as Error).message);
|
||||
}
|
||||
};
|
||||
|
||||
// Connect/Create Wallet handlers
|
||||
const handleConnectWallet = async () => {
|
||||
const _handleConnectWallet = async () => {
|
||||
if (accounts.length === 0) setCreateWalletModalVisible(true);
|
||||
else await connectWallet();
|
||||
};
|
||||
|
||||
const handleCreateWallet = async () => {
|
||||
const _handleCreateWallet = async () => {
|
||||
try {
|
||||
const { address, mnemonic } = await createWallet(walletName);
|
||||
const { _address, mnemonic } = await createWallet(walletName);
|
||||
setUserMnemonic(mnemonic); // Save for backup
|
||||
setCreateWalletModalVisible(false);
|
||||
showAlert('Wallet Created', `Save this mnemonic:\n${mnemonic}`, [{ text: 'OK', onPress: () => connectWallet() }]);
|
||||
} catch (e) { showAlert('Error', 'Failed'); }
|
||||
} catch { showAlert('Error', 'Failed'); }
|
||||
};
|
||||
|
||||
// Copy Address Handler
|
||||
@@ -613,7 +613,7 @@ const WalletScreen: React.FC = () => {
|
||||
};
|
||||
|
||||
// Import Wallet Handler
|
||||
const handleImportWallet = async () => {
|
||||
const _handleImportWallet = async () => {
|
||||
if (!importMnemonic.trim()) {
|
||||
showAlert('Error', 'Please enter a valid mnemonic');
|
||||
return;
|
||||
@@ -630,13 +630,13 @@ const WalletScreen: React.FC = () => {
|
||||
setImportWalletModalVisible(false);
|
||||
setImportMnemonic('');
|
||||
connectWallet();
|
||||
} catch (e: any) {
|
||||
showAlert('Error', e.message || 'Invalid mnemonic');
|
||||
} catch (e: unknown) {
|
||||
showAlert('Error', (e as Error).message || 'Invalid mnemonic');
|
||||
}
|
||||
};
|
||||
|
||||
// Backup Mnemonic Handler
|
||||
const handleBackupMnemonic = async () => {
|
||||
const _handleBackupMnemonic = async () => {
|
||||
if (!selectedAccount) {
|
||||
showAlert('No Wallet', 'Please create or import a wallet first.');
|
||||
return;
|
||||
@@ -677,8 +677,8 @@ const WalletScreen: React.FC = () => {
|
||||
await switchNetwork(network);
|
||||
setNetworkSelectorVisible(false);
|
||||
showAlert('Success', `Switched to ${NETWORKS[network].displayName}`);
|
||||
} catch (e: any) {
|
||||
showAlert('Error', e.message || 'Failed to switch network');
|
||||
} catch (e: unknown) {
|
||||
showAlert('Error', (e as Error).message || 'Failed to switch network');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -825,7 +825,7 @@ const WalletScreen: React.FC = () => {
|
||||
{/* Dynamic Token List */}
|
||||
{allTokens
|
||||
.filter(t => !hiddenTokens.includes(t.symbol))
|
||||
.map((token, index) => {
|
||||
.map((token, _index) => {
|
||||
|
||||
const changeColor = token.change24h >= 0 ? '#22C55E' : '#EF4444';
|
||||
const changePrefix = token.change24h >= 0 ? '+' : '';
|
||||
@@ -1099,7 +1099,7 @@ const WalletScreen: React.FC = () => {
|
||||
if (accounts.length <= 1) {
|
||||
setWalletSelectorVisible(false);
|
||||
}
|
||||
} catch (err) {
|
||||
} catch {
|
||||
if (Platform.OS === 'web') {
|
||||
window.alert('Failed to delete wallet');
|
||||
} else {
|
||||
|
||||
@@ -43,7 +43,7 @@ const DelegationScreen: React.FC = () => {
|
||||
|
||||
const [delegates, setDelegates] = useState<Delegate[]>([]);
|
||||
const [userDelegations, setUserDelegations] = useState<UserDelegation[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [_loading, setLoading] = useState(false);
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const [selectedView, setSelectedView] = useState<'explore' | 'my-delegations'>('explore');
|
||||
const [selectedDelegate, setSelectedDelegate] = useState<Delegate | null>(null);
|
||||
|
||||
@@ -22,7 +22,7 @@ interface ElectionInfo {
|
||||
totalVotes: number;
|
||||
}
|
||||
|
||||
interface Candidate {
|
||||
interface _Candidate {
|
||||
address: string;
|
||||
name: string;
|
||||
votes: number;
|
||||
@@ -32,7 +32,7 @@ interface Candidate {
|
||||
// Mock data removed - using dynamicCommissionCollective pallet for elections
|
||||
|
||||
const ElectionsScreen: React.FC = () => {
|
||||
const { api, isApiReady } = usePezkuwi();
|
||||
const { api, isApiReady, error: connectionError } = usePezkuwi();
|
||||
|
||||
const [elections, setElections] = useState<ElectionInfo[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
@@ -44,7 +44,7 @@ const ForumScreen: React.FC = () => {
|
||||
|
||||
const [categories, setCategories] = useState<Category[]>([]);
|
||||
const [discussions, setDiscussions] = useState<Discussion[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [_loading, setLoading] = useState(false);
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
|
||||
@@ -28,14 +28,14 @@ interface Proposal {
|
||||
// Mock data removed - using real blockchain queries from democracy pallet
|
||||
|
||||
const ProposalsScreen: React.FC = () => {
|
||||
const { api, isApiReady, selectedAccount, error: connectionError } = usePezkuwi();
|
||||
const { api, isApiReady, selectedAccount: _selectedAccount, error: connectionError } = usePezkuwi();
|
||||
|
||||
const [proposals, setProposals] = useState<Proposal[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const [selectedFilter, setSelectedFilter] = useState<'all' | 'active' | 'passed' | 'rejected'>('all');
|
||||
|
||||
const formatBalance = (balance: string, decimals: number = 12): string => {
|
||||
const _formatBalance = (balance: string, decimals: number = 12): string => {
|
||||
const value = BigInt(balance);
|
||||
const divisor = BigInt(10 ** decimals);
|
||||
const wholePart = value / divisor;
|
||||
@@ -51,7 +51,7 @@ const ProposalsScreen: React.FC = () => {
|
||||
// Fetch democracy referenda
|
||||
if (api.query.democracy?.referendumInfoOf) {
|
||||
const referendaData = await api.query.democracy.referendumInfoOf.entries();
|
||||
const parsedProposals: Proposal[] = referendaData.map(([key, value]: any) => {
|
||||
const parsedProposals: Proposal[] = referendaData.map(([key, value]: [{ args: [{ toNumber(): number }] }, { unwrap(): { isOngoing?: boolean; asOngoing?: { tally?: { ayes?: { toString(): string }; nays?: { toString(): string } }; proposalHash?: { toString(): string }; end?: { toNumber(): number } } } }]) => {
|
||||
const index = key.args[0].toNumber();
|
||||
const info = value.unwrap();
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ const TreasuryScreen: React.FC = () => {
|
||||
// Fetch treasury proposals
|
||||
if (api.query.treasury?.proposals) {
|
||||
const proposalsData = await api.query.treasury.proposals.entries();
|
||||
const parsedProposals: TreasuryProposal[] = proposalsData.map(([key, value]: any) => {
|
||||
const parsedProposals: TreasuryProposal[] = proposalsData.map(([key, value]: [{ args: [{ toNumber(): number }] }, { unwrap(): { beneficiary: { toString(): string }; value: { toString(): string }; proposer: { toString(): string }; bond: { toString(): string } } }]) => {
|
||||
const proposalIndex = key.args[0].toNumber();
|
||||
const proposal = value.unwrap();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user