diff --git a/mobile/App.tsx b/mobile/App.tsx index 69f5dff3..06ae87ee 100644 --- a/mobile/App.tsx +++ b/mobile/App.tsx @@ -2,8 +2,10 @@ import React, { useEffect, useState } from 'react'; import { View, ActivityIndicator, StyleSheet } from 'react-native'; import { StatusBar } from 'expo-status-bar'; import { initializeI18n } from './src/i18n'; +import { ErrorBoundary } from './src/components/ErrorBoundary'; import { LanguageProvider } from './src/contexts/LanguageContext'; import { PolkadotProvider } from './src/contexts/PolkadotContext'; +import { BiometricAuthProvider } from './src/contexts/BiometricAuthContext'; import AppNavigator from './src/navigation/AppNavigator'; import { KurdistanColors } from './src/theme/colors'; @@ -35,12 +37,16 @@ export default function App() { } return ( - - - - - - + + + + + + + + + + ); } diff --git a/mobile/src/components/ErrorBoundary.tsx b/mobile/src/components/ErrorBoundary.tsx new file mode 100644 index 00000000..5ac6494d --- /dev/null +++ b/mobile/src/components/ErrorBoundary.tsx @@ -0,0 +1,250 @@ +// ======================================== +// Error Boundary Component (React Native) +// ======================================== +// Catches React errors and displays fallback UI + +import React, { Component, ErrorInfo, ReactNode } from 'react'; +import { View, Text, TouchableOpacity, ScrollView, StyleSheet } from 'react-native'; + +interface Props { + children: ReactNode; + fallback?: ReactNode; + onError?: (error: Error, errorInfo: ErrorInfo) => void; +} + +interface State { + hasError: boolean; + error: Error | null; + errorInfo: ErrorInfo | null; +} + +/** + * Global Error Boundary for React Native + * Catches unhandled errors in React component tree + * + * @example + * + * + * + */ +export class ErrorBoundary extends Component { + constructor(props: Props) { + super(props); + this.state = { + hasError: false, + error: null, + errorInfo: null, + }; + } + + static getDerivedStateFromError(error: Error): Partial { + // Update state so next render shows fallback UI + return { + hasError: true, + error, + }; + } + + componentDidCatch(error: Error, errorInfo: ErrorInfo): void { + // Log error to console + if (__DEV__) { + console.error('ErrorBoundary caught an error:', error, errorInfo); + } + + // Update state with error details + this.setState({ + error, + errorInfo, + }); + + // Call custom error handler if provided + if (this.props.onError) { + this.props.onError(error, errorInfo); + } + + // In production, you might want to log to an error reporting service + // Example: Sentry.captureException(error); + } + + handleReset = (): void => { + this.setState({ + hasError: false, + error: null, + errorInfo: null, + }); + }; + + render(): ReactNode { + if (this.state.hasError) { + // Use custom fallback if provided + if (this.props.fallback) { + return this.props.fallback; + } + + // Default error UI for React Native + return ( + + + + {/* Error Icon */} + + ⚠️ + + + {/* Error Title */} + Something Went Wrong + + An unexpected error occurred. We apologize for the inconvenience. + + + {/* Error Details (Development Only) */} + {__DEV__ && this.state.error && ( + + + Error Details (for developers) + + + Error: + + {this.state.error.toString()} + + {this.state.errorInfo && ( + <> + + Component Stack: + + + {this.state.errorInfo.componentStack} + + + )} + + + )} + + {/* Action Buttons */} + + + Try Again + + + + {/* Support Contact */} + + If this problem persists, please contact support at{' '} + info@pezkuwichain.io + + + + + ); + } + + // No error, render children normally + return this.props.children; + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#0a0a0a', + }, + scrollView: { + flex: 1, + }, + scrollContent: { + flexGrow: 1, + justifyContent: 'center', + padding: 16, + }, + card: { + backgroundColor: '#1a1a1a', + borderRadius: 12, + borderWidth: 1, + borderColor: '#2a2a2a', + padding: 24, + }, + iconContainer: { + alignItems: 'center', + marginBottom: 16, + }, + iconText: { + fontSize: 48, + }, + title: { + fontSize: 24, + fontWeight: 'bold', + color: '#ffffff', + textAlign: 'center', + marginBottom: 12, + }, + description: { + fontSize: 16, + color: '#9ca3af', + textAlign: 'center', + marginBottom: 24, + lineHeight: 24, + }, + errorDetails: { + marginBottom: 24, + }, + errorDetailsTitle: { + fontSize: 14, + fontWeight: '600', + color: '#6b7280', + marginBottom: 12, + }, + errorBox: { + backgroundColor: '#0a0a0a', + borderRadius: 8, + borderWidth: 1, + borderColor: '#374151', + padding: 12, + }, + errorLabel: { + fontSize: 12, + fontWeight: 'bold', + color: '#ef4444', + marginBottom: 8, + }, + stackLabel: { + marginTop: 12, + }, + errorText: { + fontSize: 11, + fontFamily: 'monospace', + color: '#9ca3af', + lineHeight: 16, + }, + buttonContainer: { + marginBottom: 16, + }, + primaryButton: { + backgroundColor: '#00A94F', + borderRadius: 8, + padding: 16, + alignItems: 'center', + }, + buttonText: { + color: '#ffffff', + fontSize: 16, + fontWeight: '600', + }, + supportText: { + fontSize: 14, + color: '#6b7280', + textAlign: 'center', + lineHeight: 20, + }, + supportEmail: { + color: '#00A94F', + }, +}); diff --git a/mobile/src/components/index.ts b/mobile/src/components/index.ts index b1c311fd..d1fd2537 100644 --- a/mobile/src/components/index.ts +++ b/mobile/src/components/index.ts @@ -3,6 +3,7 @@ * Inspired by Material Design 3, iOS HIG, and Kurdistan aesthetics */ +export { ErrorBoundary } from './ErrorBoundary'; export { Card } from './Card'; export { Button } from './Button'; export { Input } from './Input'; diff --git a/mobile/src/contexts/BiometricAuthContext.tsx b/mobile/src/contexts/BiometricAuthContext.tsx index f008ff4e..d5a28420 100644 --- a/mobile/src/contexts/BiometricAuthContext.tsx +++ b/mobile/src/contexts/BiometricAuthContext.tsx @@ -85,7 +85,7 @@ export const BiometricAuthProvider: React.FC<{ children: React.ReactNode }> = ({ } } } catch (error) { - console.error('Biometric init error:', error); + if (__DEV__) console.error('Biometric init error:', error); } }; @@ -108,7 +108,7 @@ export const BiometricAuthProvider: React.FC<{ children: React.ReactNode }> = ({ // Check if app should be locked await checkAutoLock(); } catch (error) { - console.error('Error loading settings:', error); + if (__DEV__) console.error('Error loading settings:', error); } }; @@ -136,7 +136,7 @@ export const BiometricAuthProvider: React.FC<{ children: React.ReactNode }> = ({ return false; } catch (error) { - console.error('Authentication error:', error); + if (__DEV__) console.error('Authentication error:', error); return false; } }; @@ -159,7 +159,7 @@ export const BiometricAuthProvider: React.FC<{ children: React.ReactNode }> = ({ return false; } catch (error) { - console.error('Enable biometric error:', error); + if (__DEV__) console.error('Enable biometric error:', error); return false; } }; @@ -173,7 +173,7 @@ export const BiometricAuthProvider: React.FC<{ children: React.ReactNode }> = ({ await AsyncStorage.setItem(BIOMETRIC_ENABLED_KEY, 'false'); setIsBiometricEnabled(false); } catch (error) { - console.error('Disable biometric error:', error); + if (__DEV__) console.error('Disable biometric error:', error); } }; @@ -191,7 +191,7 @@ export const BiometricAuthProvider: React.FC<{ children: React.ReactNode }> = ({ // Store in SecureStore (encrypted on device) await SecureStore.setItemAsync(PIN_CODE_KEY, hashedPin); } catch (error) { - console.error('Set PIN error:', error); + if (__DEV__) console.error('Set PIN error:', error); throw error; } }; @@ -220,7 +220,7 @@ export const BiometricAuthProvider: React.FC<{ children: React.ReactNode }> = ({ return false; } catch (error) { - console.error('Verify PIN error:', error); + if (__DEV__) console.error('Verify PIN error:', error); return false; } }; @@ -250,7 +250,7 @@ export const BiometricAuthProvider: React.FC<{ children: React.ReactNode }> = ({ await AsyncStorage.setItem(AUTO_LOCK_TIMER_KEY, minutes.toString()); setAutoLockTimerState(minutes); } catch (error) { - console.error('Set auto-lock timer error:', error); + if (__DEV__) console.error('Set auto-lock timer error:', error); } }; @@ -273,7 +273,7 @@ export const BiometricAuthProvider: React.FC<{ children: React.ReactNode }> = ({ try { await AsyncStorage.setItem(LAST_UNLOCK_TIME_KEY, Date.now().toString()); } catch (error) { - console.error('Save unlock time error:', error); + if (__DEV__) console.error('Save unlock time error:', error); } }; @@ -303,7 +303,7 @@ export const BiometricAuthProvider: React.FC<{ children: React.ReactNode }> = ({ setIsLocked(false); } } catch (error) { - console.error('Check auto-lock error:', error); + if (__DEV__) console.error('Check auto-lock error:', error); // On error, lock for safety setIsLocked(true); } diff --git a/mobile/src/contexts/LanguageContext.tsx b/mobile/src/contexts/LanguageContext.tsx index e8436027..10aa5baa 100644 --- a/mobile/src/contexts/LanguageContext.tsx +++ b/mobile/src/contexts/LanguageContext.tsx @@ -29,7 +29,7 @@ export const LanguageProvider: React.FC<{ children: ReactNode }> = ({ children } const saved = await AsyncStorage.getItem(LANGUAGE_KEY); setHasSelectedLanguage(!!saved); } catch (error) { - console.error('Failed to check language selection:', error); + if (__DEV__) console.error('Failed to check language selection:', error); } }; @@ -49,7 +49,7 @@ export const LanguageProvider: React.FC<{ children: ReactNode }> = ({ children } // You may want to show a message to restart the app } } catch (error) { - console.error('Failed to change language:', error); + if (__DEV__) console.error('Failed to change language:', error); } }; diff --git a/mobile/src/contexts/PolkadotContext.tsx b/mobile/src/contexts/PolkadotContext.tsx index d821f80d..e4a5cd61 100644 --- a/mobile/src/contexts/PolkadotContext.tsx +++ b/mobile/src/contexts/PolkadotContext.tsx @@ -3,6 +3,7 @@ import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; import { KeyringPair } from '@polkadot/keyring/types'; import AsyncStorage from '@react-native-async-storage/async-storage'; +import * as SecureStore from 'expo-secure-store'; import { cryptoWaitReady } from '@polkadot/util-crypto'; import { DEFAULT_ENDPOINT } from '../../../shared/blockchain/polkadot'; @@ -56,9 +57,9 @@ export const PolkadotProvider: React.FC = ({ await cryptoWaitReady(); const kr = new Keyring({ type: 'sr25519' }); setKeyring(kr); - console.log('✅ Crypto libraries initialized'); + if (__DEV__) console.log('✅ Crypto libraries initialized'); } catch (err) { - console.error('❌ Failed to initialize crypto:', err); + if (__DEV__) console.error('❌ Failed to initialize crypto:', err); setError('Failed to initialize crypto libraries'); } }; @@ -70,7 +71,7 @@ export const PolkadotProvider: React.FC = ({ useEffect(() => { const initApi = async () => { try { - console.log('🔗 Connecting to Pezkuwi node:', endpoint); + if (__DEV__) console.log('🔗 Connecting to Pezkuwi node:', endpoint); const provider = new WsProvider(endpoint); const apiInstance = await ApiPromise.create({ provider }); @@ -81,7 +82,7 @@ export const PolkadotProvider: React.FC = ({ setIsApiReady(true); setError(null); - console.log('✅ Connected to Pezkuwi node'); + if (__DEV__) console.log('✅ Connected to Pezkuwi node'); // Get chain info const [chain, nodeName, nodeVersion] = await Promise.all([ @@ -90,10 +91,12 @@ export const PolkadotProvider: React.FC = ({ apiInstance.rpc.system.version(), ]); - console.log(`📡 Chain: ${chain}`); - console.log(`🖥️ Node: ${nodeName} v${nodeVersion}`); + if (__DEV__) { + console.log(`📡 Chain: ${chain}`); + console.log(`🖥️ Node: ${nodeName} v${nodeVersion}`); + } } catch (err) { - console.error('❌ Failed to connect to node:', err); + if (__DEV__) console.error('❌ Failed to connect to node:', err); setError(`Failed to connect to node: ${endpoint}`); setIsApiReady(false); } @@ -127,7 +130,7 @@ export const PolkadotProvider: React.FC = ({ } } } catch (err) { - console.error('Failed to load accounts:', err); + if (__DEV__) console.error('Failed to load accounts:', err); } }; @@ -161,18 +164,18 @@ export const PolkadotProvider: React.FC = ({ setAccounts(updatedAccounts); await AsyncStorage.setItem(WALLET_STORAGE_KEY, JSON.stringify(updatedAccounts)); - // Store encrypted seed separately - const seedKey = `@pezkuwi_seed_${pair.address}`; - await AsyncStorage.setItem(seedKey, mnemonicPhrase); + // SECURITY: Store encrypted seed in SecureStore (encrypted hardware-backed storage) + const seedKey = `pezkuwi_seed_${pair.address}`; + await SecureStore.setItemAsync(seedKey, mnemonicPhrase); - console.log('✅ Wallet created:', pair.address); + if (__DEV__) console.log('✅ Wallet created:', pair.address); return { address: pair.address, mnemonic: mnemonicPhrase, }; } catch (err) { - console.error('❌ Failed to create wallet:', err); + if (__DEV__) console.error('❌ Failed to create wallet:', err); throw new Error('Failed to create wallet'); } }; @@ -184,12 +187,12 @@ export const PolkadotProvider: React.FC = ({ } try { - // Load seed from storage - const seedKey = `@pezkuwi_seed_${address}`; - const mnemonic = await AsyncStorage.getItem(seedKey); + // SECURITY: Load seed from SecureStore (encrypted storage) + const seedKey = `pezkuwi_seed_${address}`; + const mnemonic = await SecureStore.getItemAsync(seedKey); if (!mnemonic) { - console.error('No seed found for address:', address); + if (__DEV__) console.error('No seed found for address:', address); return null; } @@ -197,7 +200,7 @@ export const PolkadotProvider: React.FC = ({ const pair = keyring.addFromMnemonic(mnemonic); return pair; } catch (err) { - console.error('Failed to get keypair:', err); + if (__DEV__) console.error('Failed to get keypair:', err); return null; } }; @@ -218,9 +221,9 @@ export const PolkadotProvider: React.FC = ({ await AsyncStorage.setItem(SELECTED_ACCOUNT_KEY, accounts[0].address); } - console.log(`✅ Connected with ${accounts.length} account(s)`); + if (__DEV__) console.log(`✅ Connected with ${accounts.length} account(s)`); } catch (err) { - console.error('❌ Wallet connection failed:', err); + if (__DEV__) console.error('❌ Wallet connection failed:', err); setError('Failed to connect wallet'); } }; @@ -229,7 +232,7 @@ export const PolkadotProvider: React.FC = ({ const disconnectWallet = () => { setSelectedAccount(null); AsyncStorage.removeItem(SELECTED_ACCOUNT_KEY); - console.log('🔌 Wallet disconnected'); + if (__DEV__) console.log('🔌 Wallet disconnected'); }; // Update selected account storage when it changes diff --git a/mobile/src/i18n/index.ts b/mobile/src/i18n/index.ts index e27af39a..0b7f29ed 100644 --- a/mobile/src/i18n/index.ts +++ b/mobile/src/i18n/index.ts @@ -27,7 +27,7 @@ const initializeI18n = async () => { savedLanguage = stored; } } catch (error) { - console.warn('Failed to load saved language:', error); + if (__DEV__) console.warn('Failed to load saved language:', error); } i18n @@ -58,7 +58,7 @@ export const saveLanguage = async (languageCode: string) => { await AsyncStorage.setItem(LANGUAGE_KEY, languageCode); await i18n.changeLanguage(languageCode); } catch (error) { - console.error('Failed to save language:', error); + if (__DEV__) console.error('Failed to save language:', error); } }; diff --git a/mobile/src/screens/EducationScreen.tsx b/mobile/src/screens/EducationScreen.tsx index 8572dd57..ce58ecbb 100644 --- a/mobile/src/screens/EducationScreen.tsx +++ b/mobile/src/screens/EducationScreen.tsx @@ -47,7 +47,7 @@ const EducationScreen: React.FC = () => { const allCourses = await getAllCourses(api); setCourses(allCourses); } catch (error) { - console.error('Failed to fetch courses:', error); + if (__DEV__) console.error('Failed to fetch courses:', error); } finally { setLoading(false); setRefreshing(false); @@ -64,7 +64,7 @@ const EducationScreen: React.FC = () => { const studentEnrollments = await getStudentEnrollments(selectedAccount.address); setEnrollments(studentEnrollments); } catch (error) { - console.error('Failed to fetch enrollments:', error); + if (__DEV__) console.error('Failed to fetch enrollments:', error); } }, [selectedAccount]); @@ -102,7 +102,7 @@ const EducationScreen: React.FC = () => { Alert.alert('Success', 'Successfully enrolled in course!'); fetchEnrollments(); } catch (error: any) { - console.error('Enrollment failed:', error); + if (__DEV__) console.error('Enrollment failed:', error); Alert.alert('Enrollment Failed', error.message || 'Failed to enroll in course'); } finally { setEnrolling(null); @@ -138,7 +138,7 @@ const EducationScreen: React.FC = () => { Alert.alert('Success', 'Course completed! Certificate issued.'); fetchEnrollments(); } catch (error: any) { - console.error('Completion failed:', error); + if (__DEV__) console.error('Completion failed:', error); Alert.alert('Error', error.message || 'Failed to complete course'); } }, diff --git a/mobile/src/screens/ForumScreen.tsx b/mobile/src/screens/ForumScreen.tsx index 23c293ae..189750df 100644 --- a/mobile/src/screens/ForumScreen.tsx +++ b/mobile/src/screens/ForumScreen.tsx @@ -134,7 +134,7 @@ const ForumScreen: React.FC = () => { await new Promise((resolve) => setTimeout(resolve, 500)); setThreads(MOCK_THREADS); } catch (error) { - console.error('Failed to fetch threads:', error); + if (__DEV__) console.error('Failed to fetch threads:', error); } finally { setLoading(false); setRefreshing(false); diff --git a/mobile/src/screens/GovernanceScreen.tsx b/mobile/src/screens/GovernanceScreen.tsx index 52ad6baf..9fc988d3 100644 --- a/mobile/src/screens/GovernanceScreen.tsx +++ b/mobile/src/screens/GovernanceScreen.tsx @@ -121,7 +121,7 @@ export default function GovernanceScreen() { setProposals(proposalsList); } catch (error) { - console.error('Error fetching proposals:', error); + if (__DEV__) console.error('Error fetching proposals:', error); Alert.alert('Error', 'Failed to load proposals'); } finally { setLoading(false); @@ -162,7 +162,7 @@ export default function GovernanceScreen() { ]; setElections(mockElections); } catch (error) { - console.error('Error fetching elections:', error); + if (__DEV__) console.error('Error fetching elections:', error); } }; @@ -191,7 +191,7 @@ export default function GovernanceScreen() { } }); } catch (error: any) { - console.error('Voting error:', error); + if (__DEV__) console.error('Voting error:', error); Alert.alert('Error', error.message || 'Failed to submit vote'); } finally { setVoting(false); @@ -231,7 +231,7 @@ export default function GovernanceScreen() { setVotedCandidates([]); fetchElections(); } catch (error: any) { - console.error('Election voting error:', error); + if (__DEV__) console.error('Election voting error:', error); Alert.alert('Error', error.message || 'Failed to submit vote'); } finally { setVoting(false); diff --git a/mobile/src/screens/NFTGalleryScreen.tsx b/mobile/src/screens/NFTGalleryScreen.tsx index a85674a1..44c5c70b 100644 --- a/mobile/src/screens/NFTGalleryScreen.tsx +++ b/mobile/src/screens/NFTGalleryScreen.tsx @@ -110,7 +110,7 @@ export default function NFTGalleryScreen() { setNfts(nftList); } catch (error) { - console.error('Error fetching NFTs:', error); + if (__DEV__) console.error('Error fetching NFTs:', error); } finally { setLoading(false); setRefreshing(false); diff --git a/mobile/src/screens/P2PScreen.tsx b/mobile/src/screens/P2PScreen.tsx index 93b57fe9..f48e5b47 100644 --- a/mobile/src/screens/P2PScreen.tsx +++ b/mobile/src/screens/P2PScreen.tsx @@ -64,7 +64,7 @@ const P2PScreen: React.FC = () => { setOffers(enrichedOffers); } catch (error) { - console.error('Fetch offers error:', error); + if (__DEV__) console.error('Fetch offers error:', error); } finally { setLoading(false); setRefreshing(false); @@ -191,7 +191,7 @@ const P2PScreen: React.FC = () => { variant="primary" onPress={() => { // TODO: Open trade modal - console.log('Trade with offer:', item.id); + if (__DEV__) console.log('Trade with offer:', item.id); }} style={styles.tradeButton} > diff --git a/mobile/src/screens/ReferralScreen.tsx b/mobile/src/screens/ReferralScreen.tsx index aac73623..3fce2087 100644 --- a/mobile/src/screens/ReferralScreen.tsx +++ b/mobile/src/screens/ReferralScreen.tsx @@ -67,10 +67,10 @@ const ReferralScreen: React.FC = () => { }); if (result.action === Share.sharedAction) { - console.log('Shared successfully'); + if (__DEV__) console.log('Shared successfully'); } } catch (error) { - console.error('Error sharing:', error); + if (__DEV__) console.error('Error sharing:', error); } }; diff --git a/mobile/src/screens/SignInScreen.tsx b/mobile/src/screens/SignInScreen.tsx index a39ab846..421482a8 100644 --- a/mobile/src/screens/SignInScreen.tsx +++ b/mobile/src/screens/SignInScreen.tsx @@ -27,7 +27,7 @@ const SignInScreen: React.FC = ({ onSignIn, onNavigateToSignU const handleSignIn = () => { // TODO: Implement actual authentication - console.log('Sign in:', { email, password }); + if (__DEV__) console.log('Sign in:', { email, password }); onSignIn(); }; diff --git a/mobile/src/screens/SignUpScreen.tsx b/mobile/src/screens/SignUpScreen.tsx index 80a406f6..a94fe3bb 100644 --- a/mobile/src/screens/SignUpScreen.tsx +++ b/mobile/src/screens/SignUpScreen.tsx @@ -32,7 +32,7 @@ const SignUpScreen: React.FC = ({ onSignUp, onNavigateToSignI alert('Passwords do not match!'); return; } - console.log('Sign up:', { email, password }); + if (__DEV__) console.log('Sign up:', { email, password }); onSignUp(); }; diff --git a/mobile/src/screens/StakingScreen.tsx b/mobile/src/screens/StakingScreen.tsx index c7441135..7be652dd 100644 --- a/mobile/src/screens/StakingScreen.tsx +++ b/mobile/src/screens/StakingScreen.tsx @@ -122,7 +122,7 @@ export default function StakingScreen() { estimatedAPY, }); } catch (error) { - console.error('Error fetching staking data:', error); + if (__DEV__) console.error('Error fetching staking data:', error); Alert.alert('Error', 'Failed to load staking data'); } finally { setLoading(false); @@ -155,7 +155,7 @@ export default function StakingScreen() { } }); } catch (error: any) { - console.error('Staking error:', error); + if (__DEV__) console.error('Staking error:', error); Alert.alert('Error', error.message || 'Failed to stake tokens'); } finally { setProcessing(false); @@ -189,7 +189,7 @@ export default function StakingScreen() { } }); } catch (error: any) { - console.error('Unstaking error:', error); + if (__DEV__) console.error('Unstaking error:', error); Alert.alert('Error', error.message || 'Failed to unstake tokens'); } finally { setProcessing(false); diff --git a/mobile/src/screens/SwapScreen.tsx b/mobile/src/screens/SwapScreen.tsx index b5fe9dcc..e038a58c 100644 --- a/mobile/src/screens/SwapScreen.tsx +++ b/mobile/src/screens/SwapScreen.tsx @@ -98,7 +98,7 @@ const SwapScreen: React.FC = () => { newBalances[token.symbol] = '0.0000'; } } catch (error) { - console.log(`No balance for ${token.symbol}`); + if (__DEV__) console.log(`No balance for ${token.symbol}`); newBalances[token.symbol] = '0.0000'; } } @@ -106,7 +106,7 @@ const SwapScreen: React.FC = () => { setBalances(newBalances); } catch (error) { - console.error('Failed to fetch balances:', error); + if (__DEV__) console.error('Failed to fetch balances:', error); } }, [api, isApiReady, selectedAccount]); @@ -159,7 +159,7 @@ const SwapScreen: React.FC = () => { setPoolReserves({ reserve1, reserve2 }); setState((prev) => ({ ...prev, loading: false })); } catch (error) { - console.error('Failed to fetch pool reserves:', error); + if (__DEV__) console.error('Failed to fetch pool reserves:', error); Alert.alert('Error', 'Failed to fetch pool information.'); setState((prev) => ({ ...prev, loading: false })); } @@ -214,7 +214,7 @@ const SwapScreen: React.FC = () => { setState((prev) => ({ ...prev, toAmount: toAmountFormatted })); setPriceImpact(impact); } catch (error) { - console.error('Calculation error:', error); + if (__DEV__) console.error('Calculation error:', error); setState((prev) => ({ ...prev, toAmount: '' })); } }, [state.fromAmount, state.fromToken, state.toToken, poolReserves]); @@ -326,12 +326,14 @@ const SwapScreen: React.FC = () => { // Create swap path const path = [state.fromToken.assetId, state.toToken.assetId]; - console.log('Swap params:', { - path, - amountIn, - amountOutMin, - slippage: state.slippage, - }); + if (__DEV__) { + console.log('Swap params:', { + path, + amountIn, + amountOutMin, + slippage: state.slippage, + }); + } // Create transaction const tx = api.tx.assetConversion.swapTokensForExactTokens( @@ -347,7 +349,7 @@ const SwapScreen: React.FC = () => { let unsub: (() => void) | undefined; tx.signAndSend(keyPair, ({ status, events, dispatchError }) => { - console.log('Transaction status:', status.type); + if (__DEV__) console.log('Transaction status:', status.type); if (dispatchError) { if (dispatchError.isModule) { @@ -365,7 +367,7 @@ const SwapScreen: React.FC = () => { } if (status.isInBlock || status.isFinalized) { - console.log('Transaction included in block'); + if (__DEV__) console.log('Transaction included in block'); resolve(); if (unsub) unsub(); } @@ -398,7 +400,7 @@ const SwapScreen: React.FC = () => { ] ); } catch (error: any) { - console.error('Swap failed:', error); + if (__DEV__) console.error('Swap failed:', error); Alert.alert('Swap Failed', error.message || 'An error occurred.'); setState((prev) => ({ ...prev, swapping: false })); } diff --git a/mobile/src/screens/WalletScreen.tsx b/mobile/src/screens/WalletScreen.tsx index 72622b26..2a5eb154 100644 --- a/mobile/src/screens/WalletScreen.tsx +++ b/mobile/src/screens/WalletScreen.tsx @@ -149,7 +149,7 @@ const WalletScreen: React.FC = () => { } } } catch (err) { - console.log('PEZ asset not found or not accessible'); + if (__DEV__) console.log('PEZ asset not found or not accessible'); } // Fetch USDT balance (wUSDT - asset ID 2) @@ -163,7 +163,7 @@ const WalletScreen: React.FC = () => { } } } catch (err) { - console.log('USDT asset not found or not accessible'); + if (__DEV__) console.log('USDT asset not found or not accessible'); } setBalances({ @@ -172,7 +172,7 @@ const WalletScreen: React.FC = () => { USDT: usdtBalance, }); } catch (err) { - console.error('Failed to fetch balances:', err); + if (__DEV__) console.error('Failed to fetch balances:', err); Alert.alert('Error', 'Failed to fetch token balances'); } finally { setIsLoadingBalances(false); @@ -198,7 +198,7 @@ const WalletScreen: React.FC = () => { await connectWallet(); Alert.alert('Connected', 'Wallet connected successfully!'); } catch (err) { - console.error('Failed to connect wallet:', err); + if (__DEV__) console.error('Failed to connect wallet:', err); Alert.alert('Error', 'Failed to connect wallet'); } }; @@ -220,7 +220,7 @@ const WalletScreen: React.FC = () => { [{ text: 'OK', onPress: () => connectWallet() }] ); } catch (err) { - console.error('Failed to create wallet:', err); + if (__DEV__) console.error('Failed to create wallet:', err); Alert.alert('Error', 'Failed to create wallet'); } };