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