Files
SwimBuddy/src/features/history/screens/StatsScreen.tsx
T

133 lines
4.6 KiB
TypeScript

import { useEffect, useState } from "react";
import { View, Text, ScrollView } from "react-native";
import { useTranslation } from "react-i18next";
import { getWeeklyStats, getTotalStats, getPersonalBests } from "@db/operations";
import { formatDistance } from "@utils/formatDistance";
import { formatTime } from "@utils/formatTime";
type WeeklyStats = {
count: number;
totalDistance: number;
totalDuration: number;
avgCalories: number;
};
type TotalStats = {
totalWorkouts: number;
totalDistance: number;
totalDuration: number;
};
type PersonalBest = {
distance: number;
bestTime: number;
bestSwolf: number | null;
};
export function StatsScreen() {
const { t } = useTranslation("history");
const { t: tc } = useTranslation("common");
const [weekly, setWeekly] = useState<WeeklyStats | null>(null);
const [total, setTotal] = useState<TotalStats | null>(null);
const [bests, setBests] = useState<PersonalBest[]>([]);
useEffect(() => {
loadStats();
}, []);
const loadStats = async () => {
const [w, t, b] = await Promise.all([
getWeeklyStats(),
getTotalStats(),
getPersonalBests(),
]);
setWeekly(w as WeeklyStats);
setTotal(t as TotalStats);
setBests(b as PersonalBest[]);
};
return (
<ScrollView className="flex-1 bg-white p-4">
<Text className="text-2xl font-bold text-slate-900 mb-6">{t("statistics")}</Text>
<Text className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2">
{t("thisWeek")}
</Text>
<View className="bg-sky-50 rounded-2xl p-4 mb-6">
{weekly ? (
<View className="flex-row justify-between">
<View className="items-center flex-1">
<Text className="text-2xl font-bold text-sky-600">{weekly.count}</Text>
<Text className="text-xs text-slate-500">{tc("workouts")}</Text>
</View>
<View className="items-center flex-1">
<Text className="text-2xl font-bold text-sky-600">
{formatDistance(weekly.totalDistance)}
</Text>
<Text className="text-xs text-slate-500">{tc("distance")}</Text>
</View>
<View className="items-center flex-1">
<Text className="text-2xl font-bold text-sky-600">
{formatTime(weekly.totalDuration)}
</Text>
<Text className="text-xs text-slate-500">{tc("duration")}</Text>
</View>
</View>
) : (
<Text className="text-slate-400 text-center py-4">{t("noDataYet")}</Text>
)}
</View>
<Text className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2">
{t("allTime")}
</Text>
<View className="bg-slate-50 rounded-2xl p-4 mb-6">
{total ? (
<View className="flex-row justify-between">
<View className="items-center flex-1">
<Text className="text-2xl font-bold text-slate-700">{total.totalWorkouts}</Text>
<Text className="text-xs text-slate-500">{tc("workouts")}</Text>
</View>
<View className="items-center flex-1">
<Text className="text-2xl font-bold text-slate-700">
{formatDistance(total.totalDistance)}
</Text>
<Text className="text-xs text-slate-500">{tc("distance")}</Text>
</View>
<View className="items-center flex-1">
<Text className="text-2xl font-bold text-slate-700">
{formatTime(total.totalDuration)}
</Text>
<Text className="text-xs text-slate-500">{tc("duration")}</Text>
</View>
</View>
) : (
<Text className="text-slate-400 text-center py-4">{t("noDataYet")}</Text>
)}
</View>
{bests.length > 0 && (
<>
<Text className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2">
{t("personalBests")}
</Text>
{bests.map((best) => (
<View
key={best.distance}
className="bg-green-50 rounded-2xl p-4 mb-2 flex-row justify-between items-center"
>
<Text className="text-green-700 font-medium">{tc("meter", { count: best.distance })}</Text>
<View className="items-end">
<Text className="text-green-800 font-bold">{formatTime(best.bestTime)}</Text>
{best.bestSwolf && (
<Text className="text-green-600 text-xs">{t("swolf", { value: best.bestSwolf })}</Text>
)}
</View>
</View>
))}
</>
)}
</ScrollView>
);
}