fee283b5d6
Release APK / build (push) Has been cancelled
- Replace app icon with new Charbon·Lime brand assets (icon.png + adaptive-icon.png) - Apply design tokens to theme.ts: bg #1B2433, primary/success #88D656 (lime), text1 #EEF2F5 (cream) - Add ⚙ gear button (lime) in HomeScreen header → navigates to /settings - Expand settings: git provider selector (Gitea / GitHub / GitLab) with per-provider fields - Add lib/git.ts: unified pushIncidentToGit() for Gitea, GitHub (PUT), and GitLab APIs - Update incident detail screen to use lib/git.ts and dynamic provider routing Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
161 lines
4.4 KiB
TypeScript
161 lines
4.4 KiB
TypeScript
import { useCallback, useEffect, useRef, useState } from "react";
|
|
import {
|
|
View,
|
|
Text,
|
|
FlatList,
|
|
Pressable,
|
|
ActivityIndicator,
|
|
} from "react-native";
|
|
import { router, useFocusEffect } from "expo-router";
|
|
import { getIncidents } from "@/lib/db";
|
|
import { useSettings } from "@/hooks/useSettings";
|
|
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);
|
|
const { settings, ready } = useSettings();
|
|
const didRedirect = useRef(false);
|
|
|
|
useEffect(() => {
|
|
if (!ready || didRedirect.current) return;
|
|
if (settings.homeView === "capture") {
|
|
didRedirect.current = true;
|
|
router.push("/new");
|
|
}
|
|
}, [ready, settings.homeView]);
|
|
|
|
useFocusEffect(
|
|
useCallback(() => {
|
|
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"
|
|
: "#88D65620",
|
|
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>
|
|
);
|
|
}
|