133 lines
4.6 KiB
TypeScript
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>
|
|
);
|
|
}
|