diff --git a/assets/recipe_banner.png b/assets/recipe_banner.png
new file mode 100644
index 0000000..daa1c49
Binary files /dev/null and b/assets/recipe_banner.png differ
diff --git a/components/AcctRecipeBar.jsx b/components/AcctRecipeBar.jsx
index 53e10ff..5fe12a6 100644
--- a/components/AcctRecipeBar.jsx
+++ b/components/AcctRecipeBar.jsx
@@ -1,8 +1,13 @@
import React, { useEffect, useState } from 'react';
-import { StyleSheet, View, Image, ActivityIndicator } from 'react-native';
+import {
+ StyleSheet,
+ View,
+ Image,
+ ActivityIndicator,
+ ScrollView,
+} from 'react-native';
import { MaterialCommunityIcons, FontAwesome } from '@expo/vector-icons';
import { Title, Caption, HeaderTitle, BodySmall } from './Typography';
-import Button from '../components/Button';
const RecipeSummary = ({ image, name, savedOn }) => {
const placeholderImage = require('../assets/generic_recipe.png');
@@ -73,10 +78,10 @@ const AcctRecipeBar = (props) => {
}
const savedRecipesResponse = await response.json();
setSavedRecipes(savedRecipesResponse);
- setLoading(false); // Cambiar estado a false cuando la carga se complete
+ setLoading(false);
} catch (error) {
console.log('Error fetching saved recipes: ', error);
- setLoading(false); // Cambiar estado a false en caso de error
+ setLoading(false);
}
};
fetchSavedRecipes();
@@ -103,12 +108,9 @@ const AcctRecipeBar = (props) => {
Saved Recipes
{savedRecipes.map((recipe) => (
-
+
-
+
))}
);
diff --git a/components/CategoryButton.jsx b/components/CategoryButton.jsx
index cdd035b..8a90cbe 100644
--- a/components/CategoryButton.jsx
+++ b/components/CategoryButton.jsx
@@ -1,10 +1,11 @@
import { StyleSheet, TouchableOpacity } from 'react-native';
-import { ButtonText } from './Typography';
+import { ButtonLarge } from './Typography';
+import { MaterialIcons } from '@expo/vector-icons';
-const CategoryButton = ({ title, onPress }) => {
+const CategoryButton = ({ title, icon, onPress }) => {
return (
@@ -13,14 +14,15 @@ const CategoryButton = ({ title, onPress }) => {
))
}
>
- {title || 'Button'}
+
+ {title || 'Button'}
);
};
export default CategoryButton;
-const stlyes = StyleSheet.create({
+const styes = StyleSheet.create({
categoryButton: {
alignItems: 'center',
backgroundColor: '#F7FCF8',
@@ -29,6 +31,7 @@ const stlyes = StyleSheet.create({
borderWidth: 1,
justifyContent: 'center',
paddingHorizontal: 60,
- paddingVertical: 40,
+ paddingVertical: 30,
+ gap: 5,
},
});
diff --git a/components/DietFilter.jsx b/components/DietFilter.jsx
index 65e9cfb..6f6ed45 100644
--- a/components/DietFilter.jsx
+++ b/components/DietFilter.jsx
@@ -1,5 +1,10 @@
import { useState } from 'react';
-import { FlatList, StyleSheet, TouchableOpacity, View } from 'react-native';
+import {
+ FlatList,
+ Pressable,
+ StyleSheet,
+ View,
+} from 'react-native';
import { SPOONACULAR_API_KEY } from '@env';
import { BodySmall } from './Typography';
@@ -72,8 +77,8 @@ const DietFilter = () => {
});
};
const renderItem = ({ item }) => (
-
-
+ {
>
{item.category}
-
+
);
return (
- <>
+
- >
+
);
};
@@ -105,19 +110,21 @@ const styles = StyleSheet.create({
categoryContainer: {
marginRight: 16,
marginBottom: 8,
+ marginTop: 8,
},
categoryButton: {
borderRadius: 4,
- backgroundColor: '#d2d2d2',
+ backgroundColor: '#F2F2F2',
paddingVertical: 4,
- paddingHorizontal: 2,
+ paddingHorizontal: 10,
},
categoryText: {
- color: '#121212',
+ color: '#000',
+ fontWeight: 'bold',
},
titleText: {
fontSize: 20,
- fontWeight: 'bold',
+ fontWeight: '600',
marginTop: 15,
},
selectedCategory: {
diff --git a/components/FavoriteRecipes.jsx b/components/FavoriteRecipes.jsx
index 5c624e8..e33ff1a 100644
--- a/components/FavoriteRecipes.jsx
+++ b/components/FavoriteRecipes.jsx
@@ -1,9 +1,10 @@
import React, { useContext, useEffect, useState } from 'react';
-import { Pressable, StyleSheet, Text, View } from 'react-native';
+import { Pressable, StyleSheet, View } from 'react-native';
import RecipeCard from './RecipeCard';
import { FlatList } from 'react-native';
import { useNavigation } from '@react-navigation/native';
import { USER_API_IP_URL } from '@env';
+import { Caption } from './Typography';
const FavoriteRecipesList = ({ title, scrollEnabled, numberOfRecipes }) => {
const [recipes, setRecipes] = useState([]);
@@ -47,7 +48,7 @@ const FavoriteRecipesList = ({ title, scrollEnabled, numberOfRecipes }) => {
<>
{recipes?.length === 0 ? (
- No Favorite Recipes
+ No Favorite Recipes
) : (
{
return (
- {pageTitle}
+ {pageTitle}
);
};
diff --git a/components/IngredientCard.jsx b/components/IngredientCard.jsx
index 9f49ac3..54f78b3 100644
--- a/components/IngredientCard.jsx
+++ b/components/IngredientCard.jsx
@@ -1,6 +1,6 @@
-import { StyleSheet, Text, View, Image, Pressable } from 'react-native';
+import { StyleSheet, View, Image } from 'react-native';
import React from 'react';
-import { Body, ButtonLarge, HeaderTitle } from './Typography';
+import { ButtonLarge } from './Typography';
export default IngredientCard = ({ ingredient }) => {
const { id, name, image } = ingredient;
@@ -20,7 +20,7 @@ export default IngredientCard = ({ ingredient }) => {
const styles = StyleSheet.create({
container: {
flexDirection: 'column',
- justifyContent: 'flex-start',
+ justifyContent: 'center',
alignItems: 'center',
borderColor: '#e7e7e7',
borderRadius: 18,
diff --git a/screens/AddIngredient.jsx b/screens/AddIngredient.jsx
index 42bae47..8fc60a3 100644
--- a/screens/AddIngredient.jsx
+++ b/screens/AddIngredient.jsx
@@ -1,20 +1,24 @@
import React, { useContext, useState } from 'react';
-import { StyleSheet, View, TextInput, Alert } from 'react-native';
+import { StyleSheet, View, TextInput } from 'react-native';
import { Modal } from '../components/Modal';
import Button from '../components/Button';
import { AntDesign } from '@expo/vector-icons';
import { BodySmall } from '../components/Typography';
import { USER_API_IP_URL } from '@env';
+const defaultIngredientImage =
+ 'https://cdn-icons-png.freepik.com/512/6981/6981367.png';
+
export const AddIngredientModal = ({
modalVisible,
setModalVisible,
onClose,
+ fetchIngredients,
}) => {
const { userId } = '1'; // fix when backend integrated
const [showError, setShowError] = useState('');
const [productData, setProductData] = useState({
- productName: '',
+ name: '',
quantity: 0,
});
@@ -35,25 +39,31 @@ export const AddIngredientModal = ({
};
const handleSaveProduct = async () => {
- if (!productData.productName || productData.quantity === 0) {
+ if (!productData.name || productData.quantity === 0) {
setShowError('Please, fill in all fields');
return;
}
try {
const response = await fetch(
- `http://${USER_API_IP_URL}$:8000/api/user/1/ingredients/`,
+ `http://localhost:8000/api/users/1/ingredients/`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
- body: JSON.stringify(productData),
+ body: JSON.stringify({
+ ...productData,
+ user: '1',
+ image: defaultIngredientImage,
+ }),
}
);
if (!response.ok) {
setShowError('Failed to save ingredient');
}
+ fetchIngredients();
+ setModalVisible(false);
} catch (error) {
setShowError('Error saving ingredient');
console.error('Error saving ingredient:', error);
@@ -64,7 +74,7 @@ export const AddIngredientModal = ({
- setProductData({ ...productData, productName: text })
+ setProductData({ ...productData, name: text })
}
placeholderTextColor='gray'
/>
@@ -163,7 +173,7 @@ const styles = StyleSheet.create({
},
counterContainer: {
alignSelf: 'center',
- justifyContent: 'space-between',
+ justifyContent: 'space-evenly',
alignItems: 'center',
width: '80%',
height: 60,
diff --git a/screens/FavoriteHomeSection.jsx b/screens/FavoriteHomeSection.jsx
new file mode 100644
index 0000000..b31a1db
--- /dev/null
+++ b/screens/FavoriteHomeSection.jsx
@@ -0,0 +1,27 @@
+import { ScrollView } from 'react-native-gesture-handler';
+import DietFilter from '../components/DietFilter';
+import FavoriteRecipesList from '../components/FavoriteRecipes';
+import { StyleSheet, View } from 'react-native';
+import { Title } from '../components/Typography';
+
+export const FavoriteHomeSection = (props) => {
+ return (
+
+ Favorite Recipes
+
+
+
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ favoriteRecipesContainer: {},
+
+ dietFilterContainer: {
+ marginBottom: 32,
+ },
+});
diff --git a/screens/Filter.jsx b/screens/Filter.jsx
index 6459b96..1e5bd97 100644
--- a/screens/Filter.jsx
+++ b/screens/Filter.jsx
@@ -1,12 +1,12 @@
import { useState } from 'react';
-import { StyleSheet, TouchableOpacity } from 'react-native';
-import { Text, TextInput } from 'react-native';
+import { StyleSheet } from 'react-native';
+import { TextInput } from 'react-native';
import { View } from 'react-native';
import { Calendar } from 'react-native-calendars';
import { useNavigation } from '@react-navigation/native';
-import Header from '../components/Header';
import RadioButton from '../components/RadioButton';
import Button from '../components/Button';
+import { Title } from '../components/Typography';
export const FilterScreen = () => {
const [ingredientText, setIngredientText] = useState('');
@@ -38,26 +38,15 @@ export const FilterScreen = () => {
return (
<>
-
- navigation.navigate('Home')}
- style={{ marginHorizontal: 10, marginRight: 150 }}
- >
- X
-
-
-
- Ingredient
+ Ingredient
- Meal Type
+ Meal Type
{mealTypes.map((meal, index) => (
@@ -71,7 +60,7 @@ export const FilterScreen = () => {
))}
- Planned Meal Day
+ Planned Meal Day
handleDayPressed(day)}
minDate={new Date().toISOString().split('T')[0]}
@@ -97,9 +86,12 @@ const styles = StyleSheet.create({
alignItems: 'center',
marginTop: 50,
},
+ filterTitles: {
+ marginBottom: 20,
+ },
mainContainer: {
padding: 15,
- backgroundColor: '#DEDEDE',
+ backgroundColor: '#fff',
},
title: {
fontSize: 30,
@@ -107,12 +99,15 @@ const styles = StyleSheet.create({
marginBottom: 20,
},
input: {
- padding: 5,
height: 40,
- borderRadius: 5,
- width: 250,
- backgroundColor: '#fff',
marginBottom: 10,
+ backgroundColor: '#fff',
+ paddingHorizontal: 10,
+ borderRadius: 5,
+ borderWidth: 1,
+ borderColor: '#ccc',
+ fontFamily: 'Gilroy-Medium',
+ marginBottom: 20,
},
mealTypeContainer: {
flexDirection: 'row',
diff --git a/screens/Home.jsx b/screens/Home.jsx
index 3c9cff4..ba34081 100644
--- a/screens/Home.jsx
+++ b/screens/Home.jsx
@@ -1,4 +1,5 @@
import {
+ Image,
SafeAreaView,
ScrollView,
StyleSheet,
@@ -6,15 +7,15 @@ import {
View,
} from 'react-native';
import Nav from '../components/Nav';
-import FavoriteRecipesList from '../components/FavoriteRecipes';
import CategoryButton from '../components/CategoryButton';
import Macro from '../components/Macro';
import { useNavigation } from '@react-navigation/native';
-import DietFilter from '../components/DietFilter';
import { Title } from '../components/Typography';
import { StatusBar } from 'react-native';
import { useEffect, useState } from 'react';
import { USER_API_IP_URL } from '@env';
+import { FontAwesome5 } from '@expo/vector-icons';
+import { FavoriteHomeSection } from './FavoriteHomeSection';
export const HomeScreen = () => {
const navigation = useNavigation();
@@ -43,6 +44,35 @@ export const HomeScreen = () => {
return (
+
+
+
+
+ Welcome to Zest!
+
+
+
@@ -76,23 +106,15 @@ export const HomeScreen = () => {
navigation.navigate('Ingredient')}
title='Pantry'
+ icon='kitchen'
/>
navigation.navigate('Filter')}
/>
-
-
- Favorite Recipes
-
-
-
-
-
-
-
-
+
@@ -104,10 +126,17 @@ export const HomeScreen = () => {
const styles = StyleSheet.create({
homeContainer: {
paddingHorizontal: 16,
- backgroundColor: '#f2f2f2',
+ backgroundColor: '#fff',
paddingTop: 16,
flex: 1,
},
+ columnContainer: {
+ backgroundColor: '#fff',
+ width: '100%',
+ flexDirection: 'column',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ },
macrosContainer: {
backgroundColor: '#fff',
flexDirection: 'row',
@@ -120,10 +149,10 @@ const styles = StyleSheet.create({
mainButtonsContainer: {
flexDirection: 'row',
justifyContent: 'space-around',
- marginVertical: 48,
+ // marginVertical: 48,
},
favoriteRecipesContainer: {
- marginBottom: 16,
+ // marginBottom: 16,
},
favoriteRecipesTitle: {
borderBottomWidth: 1,
diff --git a/screens/Ingredients.jsx b/screens/Ingredients.jsx
index 7dbc83f..33efc34 100644
--- a/screens/Ingredients.jsx
+++ b/screens/Ingredients.jsx
@@ -1,124 +1,53 @@
-import { SafeAreaView, ScrollView, StyleSheet, View } from 'react-native';
+import {
+ ActivityIndicator,
+ SafeAreaView,
+ ScrollView,
+ StyleSheet,
+ View,
+} from 'react-native';
import IngredientCard from '../components/IngredientCard';
import Nav from '../components/Nav';
import Search from '../components/SearchBar';
-import { useContext, useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { Body } from '../components/Typography';
import Button from '../components/Button';
import { FontAwesome5 } from '@expo/vector-icons';
import { AddIngredientModal } from './AddIngredient';
import { USER_API_IP_URL } from '@env';
-const imageUrl = 'https://cdn-icons-png.freepik.com/512/6981/6981367.png';
export const IngredientScreen = () => {
- const { userId } = '1'; // update later when backend working
+ const userId = '1'; // update later when backend working
const [modalVisible, setModalVisible] = useState(false);
const [search, setSearch] = useState('');
const [searchResults, setSearchResults] = useState([]);
const [ingredients, setIngredients] = useState([]);
+ const [loading, setLoading] = useState(true);
- const ingredientList = [
- {
- id: 1,
- name: 'Banana chips',
- image: imageUrl,
- quantity: '200g',
- user: 123,
- preference: 1,
- },
- {
- id: 2,
- name: 'Lucuma',
- image: imageUrl,
- quantity: '100ml',
- user: 456,
- preference: 2,
- },
- {
- id: 3,
- name: 'Apple',
- image: imageUrl,
- quantity: '1',
- user: 789,
- preference: 1,
- },
- {
- id: 4,
- name: 'Orange',
- image: imageUrl,
- quantity: '2',
- user: 123,
- preference: 3,
- },
- {
- id: 5,
- name: 'Lemon',
- image: imageUrl,
- quantity: '1',
- user: 456,
- preference: 2,
- },
- {
- id: 6,
- name: 'Strawberry',
- image: imageUrl,
- quantity: '150g',
- user: 789,
- preference: 1,
- },
- {
- id: 7,
- name: 'Blueberry',
- image: imageUrl,
- quantity: '100g',
- user: 123,
- preference: 3,
- },
- {
- id: 8,
- name: 'Grape',
- image: imageUrl,
- quantity: '300g',
- user: 456,
- preference: 2,
- },
- {
- id: 9,
- name: 'Kiwi',
- image: imageUrl,
- quantity: '2',
- user: 789,
- preference: 1,
- },
- {
- id: 10,
- name: 'Watermelon',
- image: imageUrl,
- quantity: '1',
- user: 123,
- preference: 3,
- },
- ];
+ const fetchIngredients = async () => {
+ try {
+ const response = await fetch(
+ `http://localhost:8000/api/users/${userId}/ingredients/`
+ );
+ const data = await response.json();
+ console.log(data);
+ setIngredients(data);
+ setSearchResults(data);
+ setLoading(false);
+ } catch (error) {
+ console.error('Error fetching ingredients:', error);
+ setLoading(false);
+ }
+ };
- // useEffect(() => {
- // const fetchIngredients = async () => {
- // setIngredients(ingredientList);
- // // try {
- // // const response = await fetch( `http://${USER_API_IP_URL}/user/${userId}/ingredients/`,);
- // // const data = await response.json();
- // // setIngredients(data);
- // // } catch (error) {
- // // console.error('Error fetching ingredients:', error);
- // // }
- // };
- // fetchIngredients();
- // }, []);
+ useEffect(() => {
+ fetchIngredients();
+ }, [userId, fetchIngredients]);
const updateSearch = (query) => {
setSearch(query);
- const filteredResults = ingredientList.filter((ingredient) =>
+ const filteredResults = ingredients.filter((ingredient) =>
ingredient.name.toLowerCase().includes(query.toLowerCase())
);
setSearchResults(filteredResults);
@@ -132,22 +61,38 @@ export const IngredientScreen = () => {
>
)}
-
-
- {searchResults.length > 0 ? (
- searchResults.map((ingredient) => (
-
- ))
- ) : (
- No ingredients found
- )}
+ {loading ? (
+
+
-
+ ) : (
+
+
+ {searchResults.length > 0 ? (
+ searchResults.map((ingredient) => (
+
+ ))
+ ) : (
+
+ No ingredients found
+
+ )}
+
+
+ )}