Files
ChatApp/apps/mobile/components/ErrorBoundary.tsx
T
byGalax b1cdc4d184 chore(mobile): phase 1 quality-review fixups
Three small follow-ups from the post-Phase-1 quality review:

  * authContext.tsx — drop the dead `userId` extraction + the `void
    userId` suppressor that masked an unused-locals warning. The session
    is already implicitly threaded through the supabase client, so no
    consumer of ensureDevice needed the value.
  * authContext.tsx — switch the device-name string concat to a
    template literal for consistency with the rest of the codebase.
  * ErrorBoundary.tsx — replace the four inline hex literals with their
    `theme/colors.ts` constants. The boundary was authored in Phase 0
    before the theme module existed; this brings it in line with every
    Phase 1 screen.
  * apps/mobile/README.md — drop the stale Phase-0 paragraph about the
    `lib/sharedSmoke.ts` canary (deleted in Phase 1) and add a short
    pointer to the env-var setup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 00:08:22 +02:00

71 lines
2.1 KiB
TypeScript

import React from 'react';
import { Pressable, StyleSheet, Text, View } from 'react-native';
import { colors } from '../theme/colors';
// Catch render errors anywhere below this boundary and show a readable
// fallback. Without it, a thrown error during render produces a white
// screen on TestFlight / production builds with no way for the user to
// recover short of force-closing the app. Mounted once at the top of
// app/_layout.tsx so it wraps every screen.
interface Props {
children: React.ReactNode;
}
interface State {
error: Error | null;
}
export class ErrorBoundary extends React.Component<Props, State> {
state: State = { error: null };
static getDerivedStateFromError(error: Error): State {
return { error };
}
componentDidCatch(error: Error, info: React.ErrorInfo): void {
// Bubble to Metro/console in dev so the redbox still shows; in prod
// builds this is the only place an exception trace surfaces.
console.error('[ErrorBoundary] caught render error', error, info.componentStack);
}
reset = (): void => {
this.setState({ error: null });
};
render(): React.ReactNode {
if (this.state.error) {
return (
<View style={styles.container}>
<Text style={styles.title}>Etwas ist schiefgelaufen</Text>
<Text style={styles.message}>{this.state.error.message}</Text>
<Pressable style={styles.button} onPress={this.reset}>
<Text style={styles.buttonText}>Erneut versuchen</Text>
</Pressable>
</View>
);
}
return this.props.children;
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: colors.bg,
padding: 24,
},
title: { color: colors.text, fontSize: 22, fontWeight: '600', marginBottom: 8 },
message: { color: colors.textMuted, textAlign: 'center', marginBottom: 24 },
button: {
backgroundColor: colors.accent,
paddingHorizontal: 20,
paddingVertical: 12,
borderRadius: 10,
},
buttonText: { color: colors.text, fontWeight: '600' },
});