import { useActionQuery } from "@agent-native/core/client/hooks"; import { useT } from "@agent-native/core/client/i18n"; import { useSetHeaderActions } from "@agent-native/toolkit/app-shell"; import { IconCalendar } from "@tabler/icons-react"; import { subDays } from "date-fns"; import { useState } from "react"; import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, ReferenceLine, } from "recharts"; import { QueryErrorState } from "@/components/QueryErrorState"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Skeleton } from "@/components/ui/skeleton"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { WeeklyCaloriesChart } from "@/components/WeeklyCaloriesChart"; import messages from "@/i18n/en-US"; import { formatLocalDate } from "@/lib/utils"; const GOAL_CALORIES = 2000; export function meta() { const description = messages.seo.analyticsDescription; return [ { title: messages.routeTitles.analytics }, { name: "description", content: description, }, { property: "og:description", content: description }, { name: "twitter:description", content: description }, ]; } export default function AnalyticsPage() { const t = useT(); const [timeRange, setTimeRange] = useState("30"); useSetHeaderActions( , ); const getStartDate = (range: string) => { if (range === "all") return "2000-01-01"; return formatLocalDate(subDays(new Date(), parseInt(range))); }; const endDate = formatLocalDate(new Date()); const startDate = getStartDate(timeRange); const historyQuery = useActionQuery("meals-history", { startDate, endDate, }); const { data: rawHistory, isLoading } = historyQuery; const history = Array.isArray(rawHistory) ? rawHistory : []; const weightHistoryQuery = useActionQuery("weights-history", { startDate, endDate, }); const { data: rawWeightHistory, isLoading: weightLoading } = weightHistoryQuery; const weightHistory = Array.isArray(rawWeightHistory) ? rawWeightHistory : []; const weightStats = { current: weightHistory.length > 0 ? weightHistory[weightHistory.length - 1].weight : 0, change: weightHistory.length >= 2 ? Math.round( (weightHistory[weightHistory.length - 1].trendWeight - weightHistory[0].trendWeight) * 10, ) / 10 : 0, lowest: weightHistory.length > 0 ? Math.min(...weightHistory.map((w) => w.weight)) : 0, highest: weightHistory.length > 0 ? Math.max(...weightHistory.map((w) => w.weight)) : 0, }; const getWeightYDomain = () => { if (weightHistory.length === 0) return [0, 200]; const ws = weightHistory.map((h) => h.weight); const min = Math.min(...ws); const max = Math.max(...ws); const padding = (max - min) * 0.3 || 5; return [Math.floor(min - padding), Math.ceil(max + padding)]; }; const stats = { average: history.length > 0 ? Math.round( history.reduce((sum, day) => sum + day.netCalories, 0) / history.length, ) : 0, highest: history.length > 0 ? Math.max(...history.map((day) => day.netCalories)) : 0, lowest: history.length > 0 ? Math.min(...history.map((day) => day.netCalories)) : 0, total: history.length, }; const tooltipStyle = { backgroundColor: "hsl(var(--card))", border: "1px solid hsl(var(--border))", borderRadius: "12px", boxShadow: "0 8px 32px rgba(0, 0, 0, 0.3)", }; return (
{stat.label}
{t("analytics.noData")}
{stat.label}
{t("analytics.trendDescription")}
)}{t("analytics.noWeightData")}
{t("analytics.noWeightDescription")}