refactor(db): separate workout plans from completed sessions

This commit is contained in:
2026-08-12 11:35:16 +02:00
parent f14c2e5827
commit 2bb4225260
16 changed files with 1222 additions and 170 deletions
+21 -21
View File
@@ -5,12 +5,12 @@ import { useNavigation } from "@react-navigation/native";
import { useFocusEffect } from "@react-navigation/native";
import type { NativeStackNavigationProp } from "@react-navigation/native-stack";
import type { HistoryStackParamList } from "@navigation/types";
import { getAllWorkouts, deleteWorkout } from "@db/operations";
import { getAllSessions, deleteSessionAndSync } from "@db/operations";
import { formatTime } from "@utils/formatTime";
import { formatDistance } from "@utils/formatDistance";
import { SwipeableRow } from "@components/SwipeableRow";
type WorkoutRow = {
type SessionRow = {
id: string;
name: string | null;
totalDistance: number | null;
@@ -24,23 +24,23 @@ export function HistoryScreen() {
const { t } = useTranslation("history");
const { t: tc } = useTranslation("common");
const navigation = useNavigation<NativeStackNavigationProp<HistoryStackParamList>>();
const [workouts, setWorkouts] = useState<WorkoutRow[]>([]);
const [sessions, setSessions] = useState<SessionRow[]>([]);
const [refreshing, setRefreshing] = useState(false);
const loadWorkouts = async () => {
const data = await getAllWorkouts();
setWorkouts((data as WorkoutRow[]).filter((w) => w.finishedAt));
const loadSessions = async () => {
const data = await getAllSessions();
setSessions(data as SessionRow[]);
};
useFocusEffect(
useCallback(() => {
loadWorkouts();
loadSessions();
}, [])
);
const onRefresh = async () => {
setRefreshing(true);
await loadWorkouts();
await loadSessions();
setRefreshing(false);
};
@@ -51,17 +51,17 @@ export function HistoryScreen() {
text: tc("delete"),
style: "destructive",
onPress: async () => {
await deleteWorkout(id);
await loadWorkouts();
await deleteSessionAndSync(id);
await loadSessions();
},
},
]);
};
const grouped = workouts.reduce<Record<string, WorkoutRow[]>>((acc, w) => {
const date = new Date(w.startedAt).toLocaleDateString();
const grouped = sessions.reduce<Record<string, SessionRow[]>>((acc, s) => {
const date = new Date(s.startedAt).toLocaleDateString();
if (!acc[date]) acc[date] = [];
acc[date].push(w);
acc[date].push(s);
return acc;
}, {});
@@ -85,25 +85,25 @@ export function HistoryScreen() {
<Text className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 px-1">
{date}
</Text>
{rows.map((w) => (
<SwipeableRow key={w.id} onDelete={() => onDelete(w.id)} deleteLabel={tc("delete")}>
{rows.map((s) => (
<SwipeableRow key={s.id} onDelete={() => onDelete(s.id)} deleteLabel={tc("delete")}>
<Pressable
onPress={() => navigation.navigate("SessionDetail", { sessionId: w.id })}
onPress={() => navigation.navigate("SessionDetail", { sessionId: s.id })}
className="p-4"
>
<View className="flex-row justify-between items-center">
<View>
<Text className="font-semibold text-slate-900">
{w.name || tc("swimSession")}
{s.name || tc("swimSession")}
</Text>
<Text className="text-slate-500 text-sm">
{formatDistance(w.totalDistance ?? 0)}
{w.totalDuration ? ` · ${formatTime(w.totalDuration)}` : ""}
{w.calories ? ` · ${tc("kcal", { count: Math.round(w.calories) })}` : ""}
{formatDistance(s.totalDistance ?? 0)}
{s.totalDuration ? ` · ${formatTime(s.totalDuration)}` : ""}
{s.calories ? ` · ${tc("kcal", { count: Math.round(s.calories) })}` : ""}
</Text>
</View>
<Text className="text-slate-400 text-xs">
{new Date(w.startedAt).toLocaleTimeString([], {
{new Date(s.startedAt).toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
})}