Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 67c132d88b | |||
| f1a4b58234 | |||
| dca76ea394 |
+1
-60
@@ -1,55 +1,13 @@
|
|||||||
import { useEffect, useState, Component } from "react";
|
import { useEffect } from "react";
|
||||||
import type { ReactNode } from "react";
|
|
||||||
import { Stack, router } from "expo-router";
|
import { Stack, router } from "expo-router";
|
||||||
import { StatusBar } from "expo-status-bar";
|
import { StatusBar } from "expo-status-bar";
|
||||||
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
||||||
import { View, Text, ScrollView } from "react-native";
|
|
||||||
import "../global.css";
|
import "../global.css";
|
||||||
import { Colors } from "@/constants/theme";
|
import { Colors } from "@/constants/theme";
|
||||||
import { useSettings } from "@/hooks/useSettings";
|
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() {
|
export default function RootLayout() {
|
||||||
const { settings, ready } = useSettings();
|
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(() => {
|
useEffect(() => {
|
||||||
if (!ready) return;
|
if (!ready) return;
|
||||||
@@ -58,23 +16,7 @@ export default function RootLayout() {
|
|||||||
}
|
}
|
||||||
}, [ready, settings.onboardingDone]);
|
}, [ready, settings.onboardingDone]);
|
||||||
|
|
||||||
if (jsError) {
|
|
||||||
return (
|
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 }}>
|
<GestureHandlerRootView style={{ flex: 1, backgroundColor: Colors.bg }}>
|
||||||
<StatusBar style="light" />
|
<StatusBar style="light" />
|
||||||
<Stack
|
<Stack
|
||||||
@@ -93,6 +35,5 @@ export default function RootLayout() {
|
|||||||
<Stack.Screen name="onboarding" options={{ headerShown: false }} />
|
<Stack.Screen name="onboarding" options={{ headerShown: false }} />
|
||||||
</Stack>
|
</Stack>
|
||||||
</GestureHandlerRootView>
|
</GestureHandlerRootView>
|
||||||
</CrashBoundary>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-4
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import {
|
import {
|
||||||
View,
|
View,
|
||||||
Text,
|
Text,
|
||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
Pressable,
|
Pressable,
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import { router } from "expo-router";
|
import { router, useFocusEffect } from "expo-router";
|
||||||
import { getIncidents } from "@/lib/db";
|
import { getIncidents } from "@/lib/db";
|
||||||
import { useSettings } from "@/hooks/useSettings";
|
import { useSettings } from "@/hooks/useSettings";
|
||||||
import type { Incident } from "@/types/incident";
|
import type { Incident } from "@/types/incident";
|
||||||
@@ -26,9 +26,11 @@ export default function HomeScreen() {
|
|||||||
}
|
}
|
||||||
}, [ready, settings.homeView]);
|
}, [ready, settings.homeView]);
|
||||||
|
|
||||||
useEffect(() => {
|
useFocusEffect(
|
||||||
|
useCallback(() => {
|
||||||
loadIncidents();
|
loadIncidents();
|
||||||
}, []);
|
}, [])
|
||||||
|
);
|
||||||
|
|
||||||
async function loadIncidents() {
|
async function loadIncidents() {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|||||||
+2
-2
@@ -46,7 +46,7 @@ const LABEL_STYLE = {
|
|||||||
letterSpacing: 0.5,
|
letterSpacing: 0.5,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
type VoiceField = "title" | "symptom" | "rootCause" | "fix";
|
type VoiceField = "title" | "service" | "symptom" | "rootCause" | "fix";
|
||||||
|
|
||||||
export default function NewIncidentScreen() {
|
export default function NewIncidentScreen() {
|
||||||
const { editId } = useLocalSearchParams<{ editId?: string }>();
|
const { editId } = useLocalSearchParams<{ editId?: string }>();
|
||||||
@@ -224,7 +224,7 @@ export default function NewIncidentScreen() {
|
|||||||
returnKeyType="next"
|
returnKeyType="next"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Text style={[LABEL_STYLE, { marginBottom: 6 }]}>Service</Text>
|
{labelRow("Service", "service")}
|
||||||
<TextInput
|
<TextInput
|
||||||
style={FIELD_STYLE}
|
style={FIELD_STYLE}
|
||||||
value={form.service}
|
value={form.service}
|
||||||
|
|||||||
Generated
+4
-4
@@ -6748,16 +6748,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-dom": {
|
"node_modules/react-dom": {
|
||||||
"version": "19.2.7",
|
"version": "19.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
|
||||||
"integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==",
|
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.27.0"
|
"scheduler": "^0.27.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^19.2.7"
|
"react": "^19.2.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-fast-compare": {
|
"node_modules/react-fast-compare": {
|
||||||
|
|||||||
@@ -27,6 +27,10 @@
|
|||||||
"react-native-screens": "~4.25.2",
|
"react-native-screens": "~4.25.2",
|
||||||
"tailwindcss": "~3.4.19"
|
"tailwindcss": "~3.4.19"
|
||||||
},
|
},
|
||||||
|
"overrides": {
|
||||||
|
"react": "19.2.3",
|
||||||
|
"react-dom": "19.2.3"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.25.0",
|
"@babel/core": "^7.25.0",
|
||||||
"@expo/metro-config": "~56.0.14",
|
"@expo/metro-config": "~56.0.14",
|
||||||
|
|||||||
Reference in New Issue
Block a user