Files
DailyMeals/meal-plan-frontend-mobile/app/(main)/(tabs)/index.tsx
Piotr Kus f15bb7a916 * Extended functionalities
* Added different UIs
2026-06-24 21:43:40 +02:00

199 lines
6.0 KiB
TypeScript

import { router } from 'expo-router';
import { ActivityIndicator, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
import { useQuery } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next';
import { fetchCategories } from '@/src/api/recipes.api';
import { ErrorView } from '@/src/components/ErrorView';
import { Screen } from '@/src/components/Screen';
import { useAuth } from '@/src/context/AuthContext';
import { useAppearance } from '@/src/context/AppearanceContext';
import { MealCategory } from '@/src/types/recipe';
import { categoryLabel } from '@/src/utils/recipe';
const CATEGORY_EMOJI: Record<MealCategory, string> = {
[MealCategory.Breakfast]: '🍳',
[MealCategory.SecondBreakfast]: '🥐',
[MealCategory.Lunch]: '🍲',
[MealCategory.Dinner]: '🌙',
};
export default function DashboardScreen() {
const { t } = useTranslation();
const { user } = useAuth();
const { colors } = useAppearance();
const categoriesQuery = useQuery({
queryKey: ['categories'],
queryFn: fetchCategories,
});
const welcome = user?.userName
? t('dashboard.welcomeNamed', { name: user.userName })
: t('dashboard.welcome');
return (
<Screen title={welcome} subtitle={t('dashboard.subtitle')}>
{categoriesQuery.isLoading ? (
<View style={styles.loading}>
<ActivityIndicator size="large" color={colors.brand} />
</View>
) : categoriesQuery.isError ? (
<ErrorView
message={t('errors.loadCategoriesFailed')}
onRetry={() => categoriesQuery.refetch()}
/>
) : (
<ScrollView contentContainerStyle={styles.list}>
<Pressable
onPress={() => router.push('/(main)/(tabs)/meals')}
style={({ pressed }) => [
styles.allCard,
{
backgroundColor: colors.brand,
opacity: pressed ? 0.9 : 1,
},
]}
>
<Text style={styles.allTitle}>{t('nav.allMeals')}</Text>
<Text style={styles.allSubtitle}>{t('dashboard.viewRecipes')}</Text>
</Pressable>
<Pressable
onPress={() => router.push('/(main)/ingredients')}
style={({ pressed }) => [
styles.card,
{
backgroundColor: colors.surface,
borderColor: colors.border,
opacity: pressed ? 0.9 : 1,
},
]}
>
<Text style={styles.emoji}>🥬</Text>
<View style={styles.cardBody}>
<Text style={[styles.cardTitle, { color: colors.text }]}>{t('nav.ingredientCatalog')}</Text>
<Text style={[styles.cardCount, { color: colors.textMuted }]}>
{t('ingredientCatalog.subtitle')}
</Text>
</View>
</Pressable>
<Pressable
onPress={() => router.push('/(main)/diet-generator')}
style={({ pressed }) => [
styles.card,
{
backgroundColor: colors.surface,
borderColor: colors.border,
opacity: pressed ? 0.9 : 1,
},
]}
>
<Text style={styles.emoji}></Text>
<View style={styles.cardBody}>
<Text style={[styles.cardTitle, { color: colors.text }]}>{t('nav.dietGenerator')}</Text>
<Text style={[styles.cardCount, { color: colors.textMuted }]}>
{t('generators.diet.subtitle')}
</Text>
</View>
</Pressable>
<Pressable
onPress={() => router.push('/(main)/recipe-generator')}
style={({ pressed }) => [
styles.card,
{
backgroundColor: colors.surface,
borderColor: colors.border,
opacity: pressed ? 0.9 : 1,
},
]}
>
<Text style={styles.emoji}>🤖</Text>
<View style={styles.cardBody}>
<Text style={[styles.cardTitle, { color: colors.text }]}>{t('nav.recipeGenerator')}</Text>
<Text style={[styles.cardCount, { color: colors.textMuted }]}>
{t('generators.recipe.subtitle')}
</Text>
</View>
</Pressable>
{(categoriesQuery.data ?? []).map((item) => (
<Pressable
key={item.category}
onPress={() => router.push(`/(main)/category/${item.category}`)}
style={({ pressed }) => [
styles.card,
{
backgroundColor: colors.surface,
borderColor: colors.border,
opacity: pressed ? 0.9 : 1,
},
]}
>
<Text style={styles.emoji}>{CATEGORY_EMOJI[item.category as MealCategory] ?? '🍽️'}</Text>
<View style={styles.cardBody}>
<Text style={[styles.cardTitle, { color: colors.text }]}>
{categoryLabel(item.category, t)}
</Text>
<Text style={[styles.cardCount, { color: colors.textMuted }]}>
{t('common.recipeCount', { count: item.count })}
</Text>
</View>
</Pressable>
))}
</ScrollView>
)}
</Screen>
);
}
const styles = StyleSheet.create({
list: {
gap: 12,
paddingBottom: 24,
},
allCard: {
borderRadius: 16,
padding: 18,
gap: 4,
},
allTitle: {
color: '#fff',
fontSize: 20,
fontWeight: '700',
},
allSubtitle: {
color: 'rgba(255,255,255,0.9)',
fontSize: 14,
},
card: {
borderWidth: 1,
borderRadius: 16,
padding: 16,
flexDirection: 'row',
alignItems: 'center',
gap: 14,
},
emoji: {
fontSize: 28,
},
cardBody: {
flex: 1,
gap: 2,
},
cardTitle: {
fontSize: 18,
fontWeight: '600',
},
cardCount: {
fontSize: 14,
},
loading: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 40,
},
});