import { useCallback, useEffect, useMemo, useState } from 'react'; import { View, Text, ActivityIndicator } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { useTranslation } from 'react-i18next'; import { apiFetch } from '../../lib/api'; import { colors } from '../../lib/theme'; type Emotion = 'stress' | 'sadness' | 'anger' | 'empty' | 'boredom' | 'other'; type UrgeLog = { id: string; timestamp: string; emotion: Emotion; wasOvercome: boolean; breathingDone: boolean; }; const WEEKDAY_LABELS = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So']; function emotionLabel(key: string, t: (k: string) => string): string { const map: Record = { stress: t('urge.emotion_stress'), sadness: t('urge.emotion_sadness'), anger: t('urge.emotion_anger'), empty: t('urge.emotion_empty'), boredom: t('urge.emotion_boredom'), other: t('urge.emotion_other'), }; return map[key] ?? key; } function StatCard({ label, value, color }: { label: string; value: string; color: string }) { return ( {value} {label} ); } export function UrgeStats() { const { t } = useTranslation(); const [logs, setLogs] = useState([]); const [loading, setLoading] = useState(true); const load = useCallback(async () => { try { setLoading(true); const data = await apiFetch('/api/urge?limit=100'); setLogs(Array.isArray(data) ? data : []); } catch { setLogs([]); } finally { setLoading(false); } }, []); useEffect(() => { load(); }, [load]); const weeklyStats = useMemo(() => { const weekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000; const thisWeek = logs.filter((log) => new Date(log.timestamp).getTime() > weekAgo); return { total: thisWeek.length, overcome: thisWeek.filter((log) => log.wasOvercome).length, breathingDone: thisWeek.filter((log) => log.breathingDone).length, }; }, [logs]); const patterns = useMemo(() => { if (logs.length < 5) return null; const weekday = new Array(7).fill(0) as number[]; const timeBlockCounts = [0, 0, 0, 0] as number[]; const emotionCount: Record = {}; for (const log of logs) { const d = new Date(log.timestamp); const jsDay = d.getDay(); const mondayIndex = jsDay === 0 ? 6 : jsDay - 1; weekday[mondayIndex]!++; const hour = d.getHours(); if (hour >= 6 && hour < 12) timeBlockCounts[0]!++; else if (hour >= 12 && hour < 18) timeBlockCounts[1]!++; else if (hour >= 18 && hour < 23) timeBlockCounts[2]!++; else timeBlockCounts[3]!++; emotionCount[log.emotion] = (emotionCount[log.emotion] ?? 0) + 1; } const maxWeekday = Math.max(...weekday, 1); const maxTime = Math.max(...timeBlockCounts, 1); const topEmotions = Object.entries(emotionCount) .sort((a, b) => b[1] - a[1]) .slice(0, 3); const peakDayIdx = weekday.indexOf(Math.max(...weekday)); const peakTimeIdx = timeBlockCounts.indexOf(Math.max(...timeBlockCounts)); const peakTimeLabel = ['morgens', 'mittags', 'abends', 'nachts'][peakTimeIdx] ?? ''; const peakDayLabel = peakDayIdx >= 5 ? 'am Wochenende' : `${WEEKDAY_LABELS[peakDayIdx]}s`; return { weekday: weekday.map((countValue, i) => ({ label: WEEKDAY_LABELS[i]!, count: countValue, pct: Math.round((countValue / maxWeekday) * 100), })), timeBlocks: [ { emoji: '🌅', label: t('urge.block_morning'), count: timeBlockCounts[0]!, pct: Math.round((timeBlockCounts[0]! / maxTime) * 100), }, { emoji: '☀️', label: t('urge.block_noon'), count: timeBlockCounts[1]!, pct: Math.round((timeBlockCounts[1]! / maxTime) * 100), }, { emoji: '🌆', label: t('urge.block_evening'), count: timeBlockCounts[2]!, pct: Math.round((timeBlockCounts[2]! / maxTime) * 100), }, { emoji: '🌙', label: t('urge.block_night'), count: timeBlockCounts[3]!, pct: Math.round((timeBlockCounts[3]! / maxTime) * 100), }, ], topEmotions, insight: `${t('urge.pattern_insight_prefix')} ${peakDayLabel} ${peakTimeLabel}.`, }; }, [logs, t]); if (loading) { return ( ); } return ( {/* Weekly counters */} {t('urge.this_week')} {patterns && ( <> {/* Insight */} {patterns.insight} {/* Weekday chart */} {t('urge.chart_weekday_title')} {patterns.weekday.map((day) => ( 0 ? Math.max(6, day.pct * 0.5) : 4, borderRadius: 5, backgroundColor: day.pct >= 80 ? '#fb7185' : day.pct >= 50 ? '#f59e0b' : '#60a5fa', marginBottom: 6, }} /> {day.label} ))} {/* Time blocks */} {t('urge.chart_time_title')} {patterns.timeBlocks.map((b) => ( {b.emoji} {b.label} {b.count} ))} {/* Top emotions */} {t('urge.chart_top_emotions')} {patterns.topEmotions.map(([emo, c]) => ( {emotionLabel(emo, t)} x{c} ))} )} ); }