managarten/apps-archived/nutriphi/apps/mobile/store/MealStore.ts
Till-JS 61d181fbc2 chore: archive inactive projects to apps-archived/
Move inactive projects out of active workspace:
- bauntown (community website)
- maerchenzauber (AI story generation)
- memoro (voice memo app)
- news (news aggregation)
- nutriphi (nutrition tracking)
- reader (reading app)
- uload (URL shortener)
- wisekeep (AI wisdom extraction)

Update CLAUDE.md documentation:
- Add presi to active projects
- Document archived projects section
- Update workspace configuration

Archived apps can be re-activated by moving back to apps/

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 07:03:59 +01:00

190 lines
5.5 KiB
TypeScript

import { create } from 'zustand';
import { Meal, MealWithItems, CreateMealInput, CreateFoodItemInput } from '../types/Database';
import { SQLiteService } from '../services/database/SQLiteService';
interface MealState {
meals: MealWithItems[];
isLoading: boolean;
error: string | null;
selectedMeal: MealWithItems | null;
// Actions
loadMeals: () => Promise<void>;
loadMealById: (id: number) => Promise<void>;
createMeal: (input: CreateMealInput) => Promise<number>;
updateMeal: (id: number, updates: Partial<Meal>) => Promise<void>;
deleteMeal: (id: number) => Promise<void>;
createFoodItem: (input: CreateFoodItemInput) => Promise<number>;
createFoodItemsBatch: (inputs: CreateFoodItemInput[]) => Promise<number[]>;
searchMeals: (query: string) => Promise<void>;
clearError: () => void;
setSelectedMeal: (meal: MealWithItems | null) => void;
clearAllMeals: () => void;
}
export const useMealStore = create<MealState>((set, get) => ({
meals: [],
isLoading: false,
error: null,
selectedMeal: null,
loadMeals: async () => {
set({ isLoading: true, error: null });
try {
const dbService = SQLiteService.getInstance();
const meals = await dbService.getAllMealsWithItems(50, 0);
set({ meals, isLoading: false });
} catch (error) {
set({
error: error instanceof Error ? error.message : 'Failed to load meals',
isLoading: false,
});
}
},
loadMealById: async (id: number) => {
set({ isLoading: true, error: null });
try {
const dbService = SQLiteService.getInstance();
const meal = await dbService.getMealWithItems(id);
console.log(`Loaded meal ${id} with photo_path:`, meal?.photo_path);
set({ selectedMeal: meal, isLoading: false });
} catch (error) {
set({
error: error instanceof Error ? error.message : 'Failed to load meal',
isLoading: false,
});
}
},
createMeal: async (input: CreateMealInput) => {
set({ isLoading: true, error: null });
try {
const dbService = SQLiteService.getInstance();
const mealId = await dbService.createMeal(input);
// Reload meals to update the list
await get().loadMeals();
set({ isLoading: false });
return mealId;
} catch (error) {
set({
error: error instanceof Error ? error.message : 'Failed to create meal',
isLoading: false,
});
throw error;
}
},
updateMeal: async (id: number, updates: Partial<Meal>) => {
set({ isLoading: true, error: null });
try {
const dbService = SQLiteService.getInstance();
await dbService.updateMeal(id, updates);
// If this is a completed analysis, reload the meal with all food items
if (updates.analysis_status === 'completed') {
const updatedMealWithItems = await dbService.getMealWithItems(id);
// Update meals in store with the full meal data
const meals = get().meals.map((meal) => (meal.id === id ? updatedMealWithItems : meal));
// Update selected meal if it's the one being updated
const selectedMeal = get().selectedMeal;
if (selectedMeal && selectedMeal.id === id) {
set({ selectedMeal: updatedMealWithItems });
}
set({ meals, isLoading: false });
} else {
// For other updates, just update the fields we have
const meals = get().meals.map((meal) => (meal.id === id ? { ...meal, ...updates } : meal));
// Update selected meal if it's the one being updated
const selectedMeal = get().selectedMeal;
if (selectedMeal && selectedMeal.id === id) {
set({ selectedMeal: { ...selectedMeal, ...updates } });
}
set({ meals, isLoading: false });
}
console.log(`Meal ${id} updated with:`, updates);
} catch (error) {
set({
error: error instanceof Error ? error.message : 'Failed to update meal',
isLoading: false,
});
}
},
deleteMeal: async (id: number) => {
set({ isLoading: true, error: null });
try {
const dbService = SQLiteService.getInstance();
await dbService.deleteMeal(id);
// Remove from meals array
const meals = get().meals.filter((meal) => meal.id !== id);
// Clear selected meal if it was deleted
const selectedMeal = get().selectedMeal;
if (selectedMeal && selectedMeal.id === id) {
set({ selectedMeal: null });
}
set({ meals, isLoading: false });
} catch (error) {
set({
error: error instanceof Error ? error.message : 'Failed to delete meal',
isLoading: false,
});
}
},
searchMeals: async (query: string) => {
set({ isLoading: true, error: null });
try {
const dbService = SQLiteService.getInstance();
const meals =
query.trim() === ''
? await dbService.getAllMeals(50, 0)
: await dbService.searchMeals(query);
set({ meals, isLoading: false });
} catch (error) {
set({
error: error instanceof Error ? error.message : 'Failed to search meals',
isLoading: false,
});
}
},
createFoodItem: async (input: CreateFoodItemInput) => {
try {
const dbService = SQLiteService.getInstance();
const foodItemId = await dbService.createFoodItem(input);
return foodItemId;
} catch (error) {
console.error('Failed to create food item:', error);
throw error;
}
},
createFoodItemsBatch: async (inputs: CreateFoodItemInput[]) => {
try {
const dbService = SQLiteService.getInstance();
const foodItemIds = await dbService.createFoodItemsBatch(inputs);
return foodItemIds;
} catch (error) {
console.error('Failed to create food items batch:', error);
throw error;
}
},
clearError: () => set({ error: null }),
setSelectedMeal: (meal: MealWithItems | null) => set({ selectedMeal: meal }),
clearAllMeals: () => set({ meals: [], selectedMeal: null, error: null }),
}));