2 Commits

Author SHA1 Message Date
billisdead 67c132d88b fix: add mic to service field, refresh list on screen focus
Release APK / build (push) Has been cancelled
new.tsx: service field was missing its mic button — VoiceField type
excluded "service" and the label used a plain Text instead of labelRow().

index.tsx: incident list only loaded on mount; router.back() does not
remount the screen so new incidents never appeared. useFocusEffect
replaces the one-shot useEffect so the list reloads on every focus.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 18:51:43 +02:00
billisdead f1a4b58234 refactor: remove crash reporter from _layout.tsx
Release APK / build (push) Has been cancelled
CrashBoundary and ErrorUtils debug handler were temporary scaffolding
to identify the launch crash (react version mismatch). Removing now
that the root cause is fixed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 18:50:15 +02:00
3 changed files with 28 additions and 85 deletions
+1 -60
View File
@@ -1,55 +1,13 @@
import { useEffect, useState, Component } from "react";
import type { ReactNode } from "react";
import { useEffect } from "react";
import { Stack, router } from "expo-router";
import { StatusBar } from "expo-status-bar";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { View, Text, ScrollView } from "react-native";
import "../global.css";
import { Colors } from "@/constants/theme";
import { useSettings } from "@/hooks/useSettings";
// Catch JS errors in release mode and show them on-screen instead of
// silently crashing to desktop. Remove once the crash is identified.
class CrashBoundary extends Component<
{ children: ReactNode },
{ error: Error | null }
> {
state = { error: null };
static getDerivedStateFromError(e: Error) {
return { error: e };
}
render() {
const { error } = this.state;
if (error) {
return (
<View style={{ flex: 1, backgroundColor: "#0f1117", padding: 20, paddingTop: 60 }}>
<Text style={{ color: "#ef4444", fontSize: 16, fontWeight: "700", marginBottom: 12 }}>
CRASH copie ce texte
</Text>
<ScrollView>
<Text style={{ color: "#fff", fontSize: 11, fontFamily: "monospace" }}>
{String(error)}{"\n\n"}{(error as any).stack}
</Text>
</ScrollView>
</View>
);
}
return this.props.children;
}
}
export default function RootLayout() {
const { settings, ready } = useSettings();
const [jsError, setJsError] = useState<string | null>(null);
useEffect(() => {
const prev = (ErrorUtils as any).getGlobalHandler();
(ErrorUtils as any).setGlobalHandler((e: Error, isFatal: boolean) => {
if (isFatal) setJsError(`${String(e)}\n\n${(e as any).stack ?? ""}`);
prev?.(e, isFatal);
});
return () => (ErrorUtils as any).setGlobalHandler(prev);
}, []);
useEffect(() => {
if (!ready) return;
@@ -58,23 +16,7 @@ export default function RootLayout() {
}
}, [ready, settings.onboardingDone]);
if (jsError) {
return (
<View style={{ flex: 1, backgroundColor: "#0f1117", padding: 20, paddingTop: 60 }}>
<Text style={{ color: "#ef4444", fontSize: 16, fontWeight: "700", marginBottom: 12 }}>
FATAL JS ERROR copie ce texte
</Text>
<ScrollView>
<Text style={{ color: "#fff", fontSize: 11, fontFamily: "monospace" }}>
{jsError}
</Text>
</ScrollView>
</View>
);
}
return (
<CrashBoundary>
<GestureHandlerRootView style={{ flex: 1, backgroundColor: Colors.bg }}>
<StatusBar style="light" />
<Stack
@@ -93,6 +35,5 @@ export default function RootLayout() {
<Stack.Screen name="onboarding" options={{ headerShown: false }} />
</Stack>
</GestureHandlerRootView>
</CrashBoundary>
);
}
+6 -4
View File
@@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import {
View,
Text,
@@ -6,7 +6,7 @@ import {
Pressable,
ActivityIndicator,
} from "react-native";
import { router } from "expo-router";
import { router, useFocusEffect } from "expo-router";
import { getIncidents } from "@/lib/db";
import { useSettings } from "@/hooks/useSettings";
import type { Incident } from "@/types/incident";
@@ -26,9 +26,11 @@ export default function HomeScreen() {
}
}, [ready, settings.homeView]);
useEffect(() => {
useFocusEffect(
useCallback(() => {
loadIncidents();
}, []);
}, [])
);
async function loadIncidents() {
setLoading(true);
+2 -2
View File
@@ -46,7 +46,7 @@ const LABEL_STYLE = {
letterSpacing: 0.5,
} as const;
type VoiceField = "title" | "symptom" | "rootCause" | "fix";
type VoiceField = "title" | "service" | "symptom" | "rootCause" | "fix";
export default function NewIncidentScreen() {
const { editId } = useLocalSearchParams<{ editId?: string }>();
@@ -224,7 +224,7 @@ export default function NewIncidentScreen() {
returnKeyType="next"
/>
<Text style={[LABEL_STYLE, { marginBottom: 6 }]}>Service</Text>
{labelRow("Service", "service")}
<TextInput
style={FIELD_STYLE}
value={form.service}