managarten/apps-archived/nutriphi/apps/mobile/components/meals/MealList.tsx
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

100 lines
2.9 KiB
TypeScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useEffect, useState } from 'react';
import { FlatList, View, Text, RefreshControl } from 'react-native';
import { MealWithItems } from '../../types/Database';
import { useMealStore } from '../../store/MealStore';
import { MealCardContextMenu } from './MealCardContextMenu';
import { LoadingSpinner } from '../ui/LoadingSpinner';
import { Button } from '../Button';
import { Header } from '../ui/Header';
interface MealListProps {
onMealPress: (meal: MealWithItems) => void;
}
export const MealList: React.FC<MealListProps> = ({ onMealPress }) => {
const [refreshing, setRefreshing] = useState(false);
const { meals, isLoading, error, loadMeals, clearError } = useMealStore();
useEffect(() => {
loadMeals();
}, [loadMeals]);
const handleRefresh = async () => {
setRefreshing(true);
await loadMeals();
setRefreshing(false);
};
const renderMealItem = ({ item }: { item: MealWithItems }) => (
<MealCardContextMenu meal={item} onPress={() => onMealPress(item)} />
);
const renderEmptyState = () => (
<View className="flex-1 items-center justify-center py-20">
<Text className="mb-4 text-6xl">🍽</Text>
<Text className="mb-2 text-xl font-semibold text-gray-800 dark:text-gray-200">
No meals yet
</Text>
<Text className="px-8 text-center text-gray-600 dark:text-gray-400">
Start tracking your nutrition by taking a photo of your first meal using the camera button
below!
</Text>
</View>
);
const renderError = () => (
<View className="flex-1 items-center justify-center py-20">
<Text className="mb-4 text-4xl"></Text>
<Text className="mb-2 text-xl font-semibold text-red-600 dark:text-red-400">
Oops! Something went wrong
</Text>
<Text className="mb-6 px-8 text-center text-gray-600 dark:text-gray-400">{error}</Text>
<Button
title="Try Again"
onPress={() => {
clearError();
loadMeals();
}}
className="px-8"
/>
</View>
);
if (error && meals.length === 0) {
return renderError();
}
if (isLoading && meals.length === 0) {
return (
<View className="flex-1 items-center justify-center">
<LoadingSpinner text="Loading your meals..." />
</View>
);
}
return (
<View className="flex-1 bg-gray-50 dark:bg-gray-900">
{/* Meal List */}
<FlatList
data={meals}
renderItem={renderMealItem}
keyExtractor={(item) => item.id!.toString()}
contentContainerStyle={{
padding: 16,
flexGrow: 1,
}}
ItemSeparatorComponent={() => <View style={{ height: 16 }} />}
ListEmptyComponent={renderEmptyState}
ListHeaderComponent={<Header title="NutriPhi" />}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={handleRefresh} tintColor="#6366f1" />
}
showsVerticalScrollIndicator={false}
/>
{/* Loading Overlay */}
{isLoading && meals.length > 0 && <LoadingSpinner overlay text="Updating..." />}
</View>
);
};