import { formatDateKey } from '@/common/utils/format'; import { computeNutrition } from '@/profile/demo/demoData'; import { calculateNutritionScore } from '@/see-log/utils/nutrition'; import { getDailyTargets } from '@/see-log/utils/nutrition'; import type { Nutrition, NutritionDisplayMode, NutritionSortMode } from '@/types/nutrition'; import type { FoodLog } from '@/types/foodlog'; import { useCallback, useMemo, useState } from 'react'; export type DayScore = { date: Date; score: number }; const FUTURE_DAYS_PER_PAGE = 14; function computeDayData(logs: FoodLog[], date: Date) { const dateStr = formatDateKey(date); const dayLogs = logs.filter(l => l.date === dateStr); const totals: Nutrition = {}; const ingredients = new Set(); for (const log of dayLogs) { if (log.processingStatus !== 'completed') continue; const n = log.nutrition && Object.keys(log.nutrition).length > 0 ? log.nutrition : computeNutrition(log.ingredients); for (const [k, v] of Object.entries(n)) { totals[k as keyof Nutrition] = (totals[k as keyof Nutrition] ?? 0) + (v ?? 0); } for (const ing of log.ingredients) { ingredients.add(ing.toLowerCase()); } } const targets = getDailyTargets(date); const score = calculateNutritionScore(totals, targets, ingredients.size); return { consumed: totals, uniqueIngredients: ingredients.size, score, targets, logs: dayLogs }; } export function useFoodReview(logs: FoodLog[]) { const [selectedDate, setSelectedDate] = useState(new Date()); const [displayMode, setDisplayMode] = useState('nutrients'); const [sortMode, setSortMode] = useState('default'); const [futureDaysCount, setFutureDaysCount] = useState(FUTURE_DAYS_PER_PAGE); const dayScores = useMemo(() => { const today = new Date(); today.setHours(0, 0, 0, 0); const result: DayScore[] = []; const pastDates = new Set(logs.map(l => l.date)); const sortedPastDates = Array.from(pastDates).sort(); for (const dateStr of sortedPastDates) { const [year, month, day] = dateStr.split('-').map(Number); const d = new Date(year, month - 1, day); if (d < today) { const { score } = computeDayData(logs, d); result.push({ date: d, score }); } } for (let i = 0; i < futureDaysCount; i++) { const d = new Date(today); d.setDate(today.getDate() + i); const { score } = computeDayData(logs, d); result.push({ date: d, score }); } return result; }, [logs, futureDaysCount]); const loadMoreFutureDays = useCallback(() => { setFutureDaysCount(prev => prev + FUTURE_DAYS_PER_PAGE); }, []); const dayData = useMemo(() => computeDayData(logs, selectedDate), [logs, selectedDate]); const nutritionScore = useMemo( () => calculateNutritionScore(dayData.consumed, dayData.targets, dayData.uniqueIngredients), [dayData.consumed, dayData.targets, dayData.uniqueIngredients] ); const pendingCount = useMemo( () => dayData.logs.filter(log => log.processingStatus !== 'completed').length, [dayData.logs] ); return { selectedDate, setSelectedDate, displayMode, setDisplayMode, sortMode, setSortMode, dayScores, loadMoreFutureDays, consumed: dayData.consumed, targets: dayData.targets, logs: dayData.logs, nutritionScore, pendingCount, }; }