added implementation frontend by prompt @ 2026-02-14 05:35:18 #CODEX
This commit is contained in:
127
frontend/src/stores/diary.ts
Normal file
127
frontend/src/stores/diary.ts
Normal file
@ -0,0 +1,127 @@
|
||||
import { computed, ref } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
import BackendAPI from '@/BackendAPI.ts'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useMealsStore } from '@/stores/meals'
|
||||
import type { DayMealsByType, DiaryDay, MealType } from '@/types/domain'
|
||||
import { MEAL_TYPES } from '@/types/domain'
|
||||
import { computeDayTotals, emptyTotals } from '@/utils/nutrition'
|
||||
import { unwrapApiData } from '@/utils/api'
|
||||
|
||||
const createEmptyDay = (date: string): DiaryDay => ({
|
||||
user_id: 0,
|
||||
day_date: date,
|
||||
diary_day_id: null,
|
||||
entries: [],
|
||||
totals: emptyTotals(),
|
||||
})
|
||||
|
||||
export const useDiaryStore = defineStore('diary', () => {
|
||||
const auth = useAuthStore()
|
||||
const mealsStore = useMealsStore()
|
||||
|
||||
const currentDay = ref<DiaryDay | null>(null)
|
||||
const loading = ref(false)
|
||||
|
||||
const requireToken = (): string => {
|
||||
if (!auth.token) {
|
||||
throw new Error('User is not authenticated')
|
||||
}
|
||||
return auth.token
|
||||
}
|
||||
|
||||
const mealsByType = computed<DayMealsByType>(() => {
|
||||
const ret: DayMealsByType = {
|
||||
breakfast: null,
|
||||
lunch: null,
|
||||
dinner: null,
|
||||
}
|
||||
|
||||
for (const entry of currentDay.value?.entries ?? []) {
|
||||
const cachedMeal = mealsStore.getMealFromCache(entry.meal_id)
|
||||
ret[entry.meal_type] = cachedMeal ?? entry.meal ?? null
|
||||
}
|
||||
|
||||
return ret
|
||||
})
|
||||
|
||||
const computedTotals = computed(() => computeDayTotals(mealsByType.value))
|
||||
|
||||
const hydrateDayMeals = async (day: DiaryDay) => {
|
||||
const loadTasks: Promise<unknown>[] = []
|
||||
for (const entry of day.entries) {
|
||||
loadTasks.push(mealsStore.ensureMeal(entry.meal_id))
|
||||
}
|
||||
if (loadTasks.length > 0) {
|
||||
await Promise.all(loadTasks)
|
||||
}
|
||||
}
|
||||
|
||||
const setCurrentDay = async (day: DiaryDay) => {
|
||||
currentDay.value = day
|
||||
await hydrateDayMeals(day)
|
||||
}
|
||||
|
||||
const loadDay = async (date: string) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const token = requireToken()
|
||||
const payload = unwrapApiData<DiaryDay>(await BackendAPI.diaryDayGet(token, date, true))
|
||||
await setCurrentDay(payload)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const setMealForType = async (date: string, mealType: MealType, mealId: number) => {
|
||||
const token = requireToken()
|
||||
const payload = unwrapApiData<DiaryDay>(await BackendAPI.diaryDaySetMeal(token, date, mealType, mealId))
|
||||
await setCurrentDay(payload)
|
||||
}
|
||||
|
||||
const unsetMealForType = async (date: string, mealType: MealType) => {
|
||||
const token = requireToken()
|
||||
const payload = unwrapApiData<DiaryDay>(await BackendAPI.diaryDayUnsetMeal(token, date, mealType))
|
||||
await setCurrentDay(payload)
|
||||
}
|
||||
|
||||
const selectedMealId = (mealType: MealType): number | null => {
|
||||
const entry = currentDay.value?.entries.find((item) => item.meal_type === mealType)
|
||||
return entry?.meal_id ?? null
|
||||
}
|
||||
|
||||
const ensureCurrentDay = (date: string) => {
|
||||
if (!currentDay.value || currentDay.value.day_date !== date) {
|
||||
currentDay.value = createEmptyDay(date)
|
||||
}
|
||||
}
|
||||
|
||||
const selectedMealOptions = computed(() => {
|
||||
const map: Record<MealType, { value: number; label: string }[]> = {
|
||||
breakfast: [],
|
||||
lunch: [],
|
||||
dinner: [],
|
||||
}
|
||||
|
||||
for (const type of MEAL_TYPES) {
|
||||
map[type] = mealsStore.sortedMeals
|
||||
.filter((meal) => meal.meal_type === type)
|
||||
.map((meal) => ({ value: meal.meal_id, label: meal.name }))
|
||||
}
|
||||
|
||||
return map
|
||||
})
|
||||
|
||||
return {
|
||||
currentDay,
|
||||
loading,
|
||||
mealsByType,
|
||||
computedTotals,
|
||||
selectedMealOptions,
|
||||
selectedMealId,
|
||||
ensureCurrentDay,
|
||||
loadDay,
|
||||
setMealForType,
|
||||
unsetMealForType,
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user