Initial scaffold: Expo SDK 56, expo-router, expo-sqlite, NativeWind
This commit is contained in:
+147
@@ -0,0 +1,147 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
FlatList,
|
||||
Pressable,
|
||||
ActivityIndicator,
|
||||
} from "react-native";
|
||||
import { router } from "expo-router";
|
||||
import { getIncidents } from "@/lib/db";
|
||||
import type { Incident } from "@/types/incident";
|
||||
import { Colors } from "@/constants/theme";
|
||||
|
||||
export default function HomeScreen() {
|
||||
const [incidents, setIncidents] = useState<Incident[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
loadIncidents();
|
||||
}, []);
|
||||
|
||||
async function loadIncidents() {
|
||||
setLoading(true);
|
||||
const data = await getIncidents(10);
|
||||
setIncidents(data);
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1, backgroundColor: Colors.bg }}>
|
||||
{loading ? (
|
||||
<ActivityIndicator
|
||||
color={Colors.primary}
|
||||
style={{ marginTop: 48 }}
|
||||
/>
|
||||
) : (
|
||||
<FlatList
|
||||
data={incidents}
|
||||
keyExtractor={(item) => item.id}
|
||||
contentContainerStyle={{ padding: 16, paddingBottom: 96 }}
|
||||
ListEmptyComponent={
|
||||
<Text
|
||||
style={{
|
||||
color: Colors.textDim,
|
||||
textAlign: "center",
|
||||
marginTop: 64,
|
||||
fontSize: 15,
|
||||
}}
|
||||
>
|
||||
No incidents. Press + to log one.
|
||||
</Text>
|
||||
}
|
||||
renderItem={({ item }) => (
|
||||
<Pressable
|
||||
onPress={() => router.push(`/incident/${item.id}`)}
|
||||
style={{
|
||||
backgroundColor: Colors.surface,
|
||||
borderRadius: 8,
|
||||
padding: 16,
|
||||
marginBottom: 10,
|
||||
borderLeftWidth: 3,
|
||||
borderLeftColor:
|
||||
item.status === "open" ? Colors.warning : Colors.success,
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: 4,
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
color: Colors.text1,
|
||||
fontSize: 15,
|
||||
fontWeight: "600",
|
||||
flex: 1,
|
||||
}}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{item.title || "Untitled"}
|
||||
</Text>
|
||||
<View
|
||||
style={{
|
||||
backgroundColor:
|
||||
item.status === "open"
|
||||
? "#f59e0b20"
|
||||
: "#22c55e20",
|
||||
borderRadius: 4,
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 2,
|
||||
marginLeft: 8,
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
color:
|
||||
item.status === "open"
|
||||
? Colors.warning
|
||||
: Colors.success,
|
||||
fontSize: 11,
|
||||
fontWeight: "700",
|
||||
textTransform: "uppercase",
|
||||
}}
|
||||
>
|
||||
{item.status}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<Text
|
||||
style={{ color: Colors.text2, fontSize: 12 }}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{item.service || "—"} · {item.createdAt.slice(0, 10)}
|
||||
</Text>
|
||||
</Pressable>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* FAB */}
|
||||
<Pressable
|
||||
onPress={() => router.push("/new")}
|
||||
style={{
|
||||
position: "absolute",
|
||||
bottom: 24,
|
||||
right: 24,
|
||||
width: 56,
|
||||
height: 56,
|
||||
borderRadius: 28,
|
||||
backgroundColor: Colors.primary,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
elevation: 6,
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{ color: "#fff", fontSize: 28, lineHeight: 32 }}
|
||||
>
|
||||
+
|
||||
</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user