import { Feather } from "@expo/vector-icons"; import { reloadAppAsync } from "expo"; import React, { useState } from "react"; import { Modal, Platform, Pressable, ScrollView, StyleSheet, Text, View, useColorScheme, } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; export type ErrorFallbackProps = { error: Error; resetError: () => void; }; export function ErrorFallback({ error, resetError }: ErrorFallbackProps) { const colorScheme = useColorScheme(); const isDark = colorScheme === "dark"; const insets = useSafeAreaInsets(); const theme = { background: isDark ? "#000000" : "#FFFFFF", backgroundSecondary: isDark ? "#1C1C1E" : "#F2F2F7", text: isDark ? "#FFFFFF" : "#000000", textSecondary: isDark ? "rgba(255, 255, 255, 0.7)" : "rgba(0, 0, 0, 0.7)", link: "#007AFF", buttonText: "#FFFFFF", }; const [isModalVisible, setIsModalVisible] = useState(false); const handleRestart = async () => { try { await reloadAppAsync(); } catch (restartError) { console.error("Failed to restart app:", restartError); resetError(); } }; const formatErrorDetails = (): string => { let details = `Error: ${error.message}\n\n`; if (error.stack) { details += `Stack Trace:\n${error.stack}`; } return details; }; const monoFont = Platform.select({ ios: "Menlo", android: "monospace", default: "monospace", }); return ( {__DEV__ ? ( setIsModalVisible(true)} accessibilityLabel="View error details" accessibilityRole="button" style={({ pressed }) => [ styles.topButton, { top: insets.top + 16, backgroundColor: theme.backgroundSecondary, opacity: pressed ? 0.8 : 1, }, ]} > ) : null} Something went wrong Please reload the app to continue. [ styles.button, { backgroundColor: theme.link, opacity: pressed ? 0.9 : 1, transform: [{ scale: pressed ? 0.98 : 1 }], }, ]} > Try Again {__DEV__ ? ( setIsModalVisible(false)} > Error Details setIsModalVisible(false)} accessibilityLabel="Close error details" accessibilityRole="button" style={({ pressed }) => [ styles.closeButton, { opacity: pressed ? 0.6 : 1 }, ]} > {formatErrorDetails()} ) : null} ); } const styles = StyleSheet.create({ container: { flex: 1, width: "100%", height: "100%", justifyContent: "center", alignItems: "center", padding: 24, }, content: { alignItems: "center", justifyContent: "center", gap: 16, width: "100%", maxWidth: 600, }, title: { fontSize: 28, fontWeight: "700", textAlign: "center", lineHeight: 40, }, message: { fontSize: 16, textAlign: "center", lineHeight: 24, }, topButton: { position: "absolute", right: 16, width: 44, height: 44, borderRadius: 8, flexDirection: "row", alignItems: "center", justifyContent: "center", zIndex: 10, }, button: { paddingVertical: 16, borderRadius: 8, paddingHorizontal: 24, minWidth: 200, shadowColor: "#000", shadowOffset: { width: 0, height: 2, }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 3, }, buttonText: { fontWeight: "600", textAlign: "center", fontSize: 16, }, modalOverlay: { flex: 1, backgroundColor: "rgba(0, 0, 0, 0.5)", justifyContent: "flex-end", }, modalContainer: { width: "100%", height: "90%", borderTopLeftRadius: 16, borderTopRightRadius: 16, }, modalHeader: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", paddingHorizontal: 16, paddingTop: 16, paddingBottom: 12, borderBottomWidth: 1, }, modalTitle: { fontSize: 20, fontWeight: "600", }, closeButton: { width: 44, height: 44, alignItems: "center", justifyContent: "center", }, modalScrollView: { flex: 1, }, modalScrollContent: { padding: 16, }, errorContainer: { width: "100%", borderRadius: 8, overflow: "hidden", padding: 16, }, errorText: { fontSize: 12, lineHeight: 18, width: "100%", }, });