// ======================================== // 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', }, });