import React, { Component } from 'react'; import type { ReactNode } from 'react'; import { View, Text, StyleSheet, Pressable } from 'react-native'; type ErrorBoundaryProps = { children: ReactNode; onError?: (error: Error, errorInfo: React.ErrorInfo) => void; onReset?: () => void; fallback?: (error: Error, resetError: () => void) => ReactNode; }; type ErrorBoundaryState = { hasError: boolean; error: Error | null; }; /** * Error Boundary component for catching errors in custom tooltips * Prevents the entire app from crashing when a custom tooltip renderer fails */ export class CoachmarkErrorBoundary extends Component< ErrorBoundaryProps, ErrorBoundaryState > { constructor(props: ErrorBoundaryProps) { super(props); this.state = { hasError: false, error: null, }; } static getDerivedStateFromError(error: Error): ErrorBoundaryState { return { hasError: true, error, }; } componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { console.error('[Coachmark] Error caught in boundary:', error, errorInfo); this.props.onError?.(error, errorInfo); } resetError = () => { this.setState({ hasError: false, error: null, }); this.props.onReset?.(); }; render() { if (this.state.hasError && this.state.error) { if (this.props.fallback) { return this.props.fallback(this.state.error, this.resetError); } return ( ⚠️ Tooltip Error {this.state.error.message || 'An error occurred rendering the tooltip'} Dismiss ); } return this.props.children; } } const styles = StyleSheet.create({ errorContainer: { justifyContent: 'center', alignItems: 'center', padding: 20, }, errorBox: { backgroundColor: '#fff', borderRadius: 12, padding: 20, maxWidth: 320, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.25, shadowRadius: 8, elevation: 5, borderWidth: 2, borderColor: '#ff4444', }, errorTitle: { fontSize: 18, fontWeight: '700', color: '#ff4444', marginBottom: 8, textAlign: 'center', }, errorMessage: { fontSize: 14, color: '#333', marginBottom: 16, textAlign: 'center', lineHeight: 20, }, resetButton: { backgroundColor: '#ff4444', borderRadius: 8, paddingVertical: 10, paddingHorizontal: 20, alignItems: 'center', }, resetButtonText: { color: '#fff', fontSize: 14, fontWeight: '600', }, });