diff --git a/backend/src/controllers/MetricasController.ts b/backend/src/controllers/MetricasController.ts index d43d885..8608331 100644 --- a/backend/src/controllers/MetricasController.ts +++ b/backend/src/controllers/MetricasController.ts @@ -1,6 +1,15 @@ import User from "../models/mongo/User"; import pg from "../databases/postgres"; - +export interface MetricasProps { + calorias: number; + proteinas: number; + gordura: number; + carboidrato: number; + acucar: number; + IMC: number; + TMB: number; + aguaIdeal: number; +} class MetricasController { // Criar um novo usuário async calculateMetricas(idUsuario: string) { @@ -30,18 +39,21 @@ class MetricasController { const carboidrato = parseFloat((peso * 4.25).toFixed(2)); const acucar = parseFloat((peso / 0.66).toFixed(2)); - for (const users of userMongo) { - users.macroIdeal.Caloria = calorias; - users.macroIdeal.Proteina = proteinas; - users.macroIdeal.gordura = gordura; - users.macroIdeal.Carboidrato = carboidrato; - users.macroIdeal.acucar = acucar; - users.metrica.ImcIdeal = IMC; - users.metrica.TmbIdeal = TMB; - users.ingestaoAgua.ingestaoIdeal = aguaIdeal; - users.save(); + const MetricasValues: MetricasProps = { + calorias, + proteinas, + gordura, + carboidrato, + acucar, + IMC, + TMB, + aguaIdeal + } + + return MetricasValues + } catch (error) { console.error("Erro ao calcular as métricas do usuário:", error); return @@ -49,6 +61,9 @@ class MetricasController { } + + + } export default new MetricasController(); diff --git a/backend/src/controllers/alimentosController.ts b/backend/src/controllers/alimentosController.ts index ade798b..0e644c0 100644 --- a/backend/src/controllers/alimentosController.ts +++ b/backend/src/controllers/alimentosController.ts @@ -25,9 +25,29 @@ class AlimentosController { } async findAlimento(req: Request, res: Response): Promise { + try { + console.log("RECEBIDO"); + const { barcode } = req.params; + console.log(barcode, "BARCODE BACK"); + + const alimentos = await pg.query( + `SELECT * FROM "Alimentos" WHERE "barcode" = $1`, + [barcode] + ); + console.log(alimentos.rows); + if (alimentos.rows.length > 0) { + return res.status(201).json(alimentos.rows[0]); + } else { + return res.status(204).json({ message: "Alimento não encontrado" }); + } + } catch (error: any) { + return res.status(500).json(error.message); + } + } + + async searchAlimentoByName(req: Request, res: Response): Promise { try { const { id,nomeProduto } = req.params; - console.log(nomeProduto, "BUSCANDO ESSE ALIMENTO NO BANCO"); const alimentos = await pg.query( ` SELECT DISTINCT A."nomeProduto", A."idProduto" ,A.barcode,A."Proteina",A."Caloria", A."Carboidrato", A.gordura, A.sodio, A.acucar, diff --git a/backend/src/controllers/cadastroController.ts b/backend/src/controllers/cadastroController.ts index 82ee586..b7dd4fc 100644 --- a/backend/src/controllers/cadastroController.ts +++ b/backend/src/controllers/cadastroController.ts @@ -25,8 +25,8 @@ class CadastroController { return res .status(201) .json({ message: "Usuário criado com sucesso!", idUserPostgres }); - } catch (error) { - console.error("Erro ao criar usuário:", error); + } catch (error:any) { + console.error("Erro ao criar usuário:", error.message); return res.status(500).json({ message: "Erro ao criar usuário", error }); } } diff --git a/backend/src/controllers/dashboardController.ts b/backend/src/controllers/dashboardController.ts index e1033b9..ccf9442 100644 --- a/backend/src/controllers/dashboardController.ts +++ b/backend/src/controllers/dashboardController.ts @@ -11,6 +11,7 @@ class DashboardController { const { data } = req.body; const { userId } = req.params; + const data_atual = moment(data).format("YYYY-MM-DD"); const userPG = await User.find({ idUser: userId }); @@ -27,6 +28,7 @@ class DashboardController { data_atual: data_atual, usuario: usersPG?.id, }); + if (buscandoUsuario) { usuarioEncontrado = buscandoUsuario; } @@ -40,8 +42,7 @@ class DashboardController { const userMongo = await User.findById(usuarioEncontrado.usuario); const userPotsgres = await pg.query( - `select "nomeUsuario",peso,altura,genero,meta,"TMB" FROM "User" WHERE "idUsuario" = $1`, - [userMongo?.idUser] + `select "nomeUsuario",peso,altura,genero,meta,"TMB" FROM "User" WHERE "idUsuario" = ${userId}`, ); return res diff --git a/backend/src/controllers/dataController.ts b/backend/src/controllers/dataController.ts index cb941b1..e6743f9 100644 --- a/backend/src/controllers/dataController.ts +++ b/backend/src/controllers/dataController.ts @@ -3,7 +3,7 @@ import pg from '../databases/postgres' import Data from "../models/mongo/Data"; import User from "../models/mongo/User"; import moment from 'moment'; - +import MetricasController, { MetricasProps } from "./MetricasController"; class DataController { public dayOfTheWeek = (day: number): string => { @@ -41,7 +41,7 @@ class DataController { const { userId } = req.params; const { data } = req.body const data_atual = moment(data).format("YYYY-MM-DD") - console.log("RECEBIDO!",data_atual,userId) + console.log("RECEBIDO!", data_atual, userId) // VERIFICA SE O USUÁRIO EXISTE NA TABELA POSTGRESQL const users = await pg.query(`SELECT * FROM "User" WHERE "idUsuario" = $1`, [userId]); @@ -49,16 +49,18 @@ class DataController { return res.status(404).json({ message: "Usuário não encontrado" }); } + const metricasData: MetricasProps | undefined = await MetricasController.calculateMetricas(userId); + const userData = await new User({ idUser: userId, consumoAlimentos: [], macroIdeal: { - Proteina: 300, - Caloria: 300, - Carboidrato: 300, - gordura: 300, + Proteina: metricasData?.proteinas, + Caloria: metricasData?.calorias, + Carboidrato: metricasData?.carboidrato, + gordura: metricasData?.gordura, sodio: 300, - acucar: 300, + acucar: metricasData?.acucar, }, macroReal: { Proteina: 0, @@ -71,11 +73,11 @@ class DataController { metrica: { ImcAtual: 0, TmbAtual: 0, - ImcIdeal: 0, - TmbIdeal: 0, + ImcIdeal: metricasData?.IMC, + TmbIdeal: metricasData?.TMB, }, ingestaoAgua: { - ingestaoIdeal: 3000, + ingestaoIdeal: metricasData?.aguaIdeal, ingestaoAtual: 0, }, }).save(); diff --git a/backend/src/controllers/editProfileController.ts b/backend/src/controllers/editProfileController.ts index a253f59..a137d51 100644 --- a/backend/src/controllers/editProfileController.ts +++ b/backend/src/controllers/editProfileController.ts @@ -25,12 +25,6 @@ class EditProfileController { return res.status(404).json({ message: "Usuário não encontrado" }); } - try { - MetricasController.calculateMetricas(idUsuario); - } catch (error: any) { - console.log("Erro ao calcular métricas do usuário"); - } - return res.status(200).json({ message: "Usuário atualizado com sucesso!", user: updatedUser.rows[0], diff --git a/backend/src/controllers/loginController.ts b/backend/src/controllers/loginController.ts index 6ab61fd..d11c2c3 100644 --- a/backend/src/controllers/loginController.ts +++ b/backend/src/controllers/loginController.ts @@ -20,6 +20,7 @@ class LoginController { // Verificar se o usuário existe if (user.rows.length === 0) { + console.log("USUÁRIO NÃO ENCONTRADO!") return res.status(404).json({ message: "Usuário não encontrado" }); } @@ -37,6 +38,9 @@ class LoginController { id: foundUser.idUsuario, nomeUsuario: foundUser.nomeUsuario, email: foundUser.email, + peso: foundUser.peso, + altura:foundUser.altura, + genero:foundUser.genero }, }); } catch (error) { diff --git a/backend/src/databases/postgres.ts b/backend/src/databases/postgres.ts index 9430a37..25117e7 100644 --- a/backend/src/databases/postgres.ts +++ b/backend/src/databases/postgres.ts @@ -4,10 +4,10 @@ const password = process.env.PG_PASS || 'your_pg_password'; console.log(password) const connectionString = `postgresql://postgres.wnvipfgsewkkjiiwsoic:${password}@aws-0-us-west-1.pooler.supabase.com:6543/postgres` -const postgresLocal = `postgresql://postgres:2202@localhost:5432/Dnutri` +const postgresLocal = `postgresql://postgres:123@localhost:5432/Dnutri` const pool = new Pool({ - connectionString: connectionString, + connectionString: postgresLocal, }); async function connectToPostgres() { diff --git a/backend/src/models/mongo/User.ts b/backend/src/models/mongo/User.ts index edf871b..f7a576d 100644 --- a/backend/src/models/mongo/User.ts +++ b/backend/src/models/mongo/User.ts @@ -33,7 +33,8 @@ export interface IAgua { } // Interface para User -interface IUser { +export interface IUser { + id:Schema.Types.ObjectId idUser:number; consumoAlimentos: IAlimento[]; macroIdeal: IMacroNutrientes; diff --git a/backend/src/routes/alimento.ts b/backend/src/routes/alimento.ts index ccd37ac..0d30a0c 100644 --- a/backend/src/routes/alimento.ts +++ b/backend/src/routes/alimento.ts @@ -7,7 +7,8 @@ const FoodRouter = Router(); FoodRouter.post("/alimentos", AlimentoController.createAlimento); FoodRouter.get("/alimentos/:id/:quantity", AlimentoController.buscarAlimentos); -FoodRouter.get("/findAlimento/:id/:nomeProduto", AlimentoController.findAlimento); +FoodRouter.get("/searchAlimentoByName/:id/:nomeProduto", AlimentoController.searchAlimentoByName); +FoodRouter.get("/findAlimento/:barcode", AlimentoController.findAlimento); FoodRouter.post("/addAlimento/", AlimentoController.addAlimento); FoodRouter.post("/consumidos", AlimentoController.alimentosConsumidos); FoodRouter.get("/favoritos/:id", AlimentoController.favoritosAlimentos); diff --git a/backend/src/routes/dashboardRoutes.ts b/backend/src/routes/dashboardRoutes.ts index 19d3d76..9fb618c 100644 --- a/backend/src/routes/dashboardRoutes.ts +++ b/backend/src/routes/dashboardRoutes.ts @@ -5,10 +5,7 @@ const DashboardRouter = express.Router(); // Rotas para dados diários //DashboardRouter.get("/data/:userId/", DataController.getDataById); -DashboardRouter.post( - "/dashboard/:userId", - dashboardController.getUserDataByDate -); +DashboardRouter.post("/dashboard/:userId",dashboardController.getUserDataByDate); //DashboardRouter.delete("/data/:userId", DataController.deleteData); export default DashboardRouter; diff --git a/frontend/App.tsx b/frontend/App.tsx index c30b14a..d67e8e3 100644 --- a/frontend/App.tsx +++ b/frontend/App.tsx @@ -2,7 +2,8 @@ import Routes from "./src/routes"; import React, { useEffect } from "react"; import * as SplashScreen from "expo-splash-screen"; import { useFonts, Signika_400Regular } from "@expo-google-fonts/signika"; - +import { UserProvider } from "./src/context/userContext"; +import { DateProvider } from "./src/context/dateContext"; SplashScreen.preventAutoHideAsync(); // Manter a splash screen até as fontes serem carregadas export default function App() { @@ -21,5 +22,12 @@ export default function App() { if (!fontsLoaded) { return null; // Retorna null enquanto as fontes estão carregando } - return ; + return ( + + + + + + + ) } diff --git a/frontend/src/components/AguaConsumo/index.tsx b/frontend/src/components/AguaConsumo/index.tsx index 4f87ceb..e093cb9 100644 --- a/frontend/src/components/AguaConsumo/index.tsx +++ b/frontend/src/components/AguaConsumo/index.tsx @@ -3,6 +3,7 @@ import { View, Text, Dimensions, StyleSheet, SafeAreaView, Image, TouchableOpaci import { IUser } from '../../types/userDiary'; import { StackNavigationProp } from "@react-navigation/stack"; import { RootStackParamList } from "../../../types"; +import AsyncStorage from '@react-native-async-storage/async-storage'; type AguaComponentNavigationProp = StackNavigationProp; interface UserProps { @@ -15,7 +16,6 @@ const screenWidth = Dimensions.get('window').width; const logo = require("../../../assets/add.png"); export default function AguaConsumo({ userMG, navigation }: UserProps) { - let aguaIdeal = userMG?.ingestaoAgua?.ingestaoIdeal || 0 let aguaReal = userMG?.ingestaoAgua?.ingestaoAtual || 0 let idealMetrica = "ml" diff --git a/frontend/src/context/dateContext.tsx b/frontend/src/context/dateContext.tsx new file mode 100644 index 0000000..3f3faf0 --- /dev/null +++ b/frontend/src/context/dateContext.tsx @@ -0,0 +1,24 @@ +// src/context/DateContext.tsx +import React, { createContext, useState, ReactNode } from 'react'; +import moment from 'moment'; + +interface DateContextData { + date: string; + setDate: React.Dispatch>; +} + +export const DateContext = createContext(undefined); + +interface DateProviderProps { + children: ReactNode; +} + +export const DateProvider = ({ children }: DateProviderProps) => { + const [date, setDate] = useState(moment.utc().format("YYYY-MM-DD")); + + return ( + + {children} + + ); +}; diff --git a/frontend/src/context/userContext.tsx b/frontend/src/context/userContext.tsx new file mode 100644 index 0000000..5c736d1 --- /dev/null +++ b/frontend/src/context/userContext.tsx @@ -0,0 +1,36 @@ +// src/context/UserContext.tsx +import React, { createContext, useState, ReactNode, useEffect } from 'react'; +import AsyncStorage from '@react-native-async-storage/async-storage'; +import { IuserLogin } from '../types/user'; + +interface UserContextData { + user: IuserLogin | null; + setUser: React.Dispatch>; +} + +export const UserContext = createContext(undefined); + +interface UserProviderProps { + children: ReactNode; +} + +export const UserProvider = ({ children }: UserProviderProps) => { + const [user, setUser] = useState(null); + + useEffect(() => { + // Verifica se há um usuário salvo no AsyncStorage ao iniciar a aplicação + const loadUser = async () => { + const storedUser = await AsyncStorage.getItem('user'); + if (storedUser) { + setUser(JSON.parse(storedUser)); + } + }; + loadUser(); + }, []); + + return ( + + {children} + + ); +}; diff --git a/frontend/src/routes/auth.routes.tsx b/frontend/src/routes/auth.routes.tsx new file mode 100644 index 0000000..5648322 --- /dev/null +++ b/frontend/src/routes/auth.routes.tsx @@ -0,0 +1,98 @@ +import AsyncStorage from "@react-native-async-storage/async-storage"; +import { createStackNavigator } from "@react-navigation/stack"; +import { useState, useEffect } from "react"; +import AguaScreen from "../screens/AguaScreen"; +import CadastroScreen from "../screens/CadastroScreen"; +import LoginScreen from "../screens/LoginScreen"; +import OnboardingScreen from "../screens/OnboardingScreen"; +import TabRoutes from "./tab.routes"; +import SelectAlimento from "../screens/SelectAlimento"; +import TabelaNutricional from "../screens/TabelaNutricional"; +import ProfileScreen from "../screens/ProfileScreen"; +import EditProfile from "../screens/EditProfile"; +import TermsOfUse from "../screens/Terms"; +import { StatusBar, TouchableOpacity, Text } from "react-native"; +import { Ionicons } from "@expo/vector-icons"; +import ScannerScreen from "../screens/BarcodeScreen"; +import ProductDetailsScreen from "../screens/ProductScreen"; +import React from "react"; +import ProductDetailsScreenPG from "../screens/ProductPG"; +import AlimentosConsumidosScreen from "../screens/AlimentosConsumidosScreen"; +import SelectRefeicao from "../screens/SelectRefeicao"; +import { IuserLogin } from "../types/user"; + +const AuthStack = createStackNavigator(); + +export default function AuthRoutes() { + const [isOnboardingCompleted, setIsOnboardingCompleted] = useState(null); + const [user, setUser] = useState(null); + + useEffect(() => { + const checkOnboardingStatus = async () => { + const completed = await AsyncStorage.getItem("onboardingCompleted"); + setIsOnboardingCompleted(completed === "true"); + + const userData = await AsyncStorage.getItem("user"); + setUser(userData ? JSON.parse(userData) : null); + }; + + checkOnboardingStatus(); + }, [user?.profileCompleted]); + + // Enquanto `AsyncStorage` está verificando as informações, retorna `null` + if (isOnboardingCompleted === null) { + return null; // Exibe um carregamento temporário enquanto a verificação ocorre + } + + return ( + ({ + headerShown: !(route.name === "Onboarding"), + headerLeft: + route.name === "Login" ? () => ( + navigation.goBack()} + style={{ + flexDirection: "row", + alignItems: "center", + marginLeft: 10, + }} + > + + Voltar + + ) : undefined, + })} + > + {/* Tela de Onboarding exibida apenas uma vez */} + {!isOnboardingCompleted && ( + + )} + + {/* Tela de Login */} + + + {/* Tela de Cadastro */} + + + ); +} diff --git a/frontend/src/routes/index.tsx b/frontend/src/routes/index.tsx index 9185be7..7862976 100644 --- a/frontend/src/routes/index.tsx +++ b/frontend/src/routes/index.tsx @@ -1,10 +1,34 @@ import StackRoutes from "./stack.routes"; import { NavigationContainer } from "@react-navigation/native"; +import TabRoutes from "./tab.routes"; +import { UserContext } from "../context/userContext"; +import { useContext } from "react"; +import AuthRoutes from "./auth.routes"; +import AsyncStorage from '@react-native-async-storage/async-storage'; + +const clearStorage = async () => { + try { + await AsyncStorage.clear(); + console.log("Armazenamento limpo com sucesso!"); + } catch (error) { + console.error("Erro ao limpar o armazenamento:", error); + } +}; + export default function Routes() { + const userContext = useContext(UserContext); + const user = userContext?.user; + return ( - + + {user ? + <> + + + : } + ); } diff --git a/frontend/src/routes/stack.routes.tsx b/frontend/src/routes/stack.routes.tsx index e02453e..ebe2e0c 100644 --- a/frontend/src/routes/stack.routes.tsx +++ b/frontend/src/routes/stack.routes.tsx @@ -2,7 +2,6 @@ import AsyncStorage from "@react-native-async-storage/async-storage"; import { createStackNavigator } from "@react-navigation/stack"; import { useState, useEffect } from "react"; import AguaScreen from "../screens/AguaScreen"; -import CadastroScreen from "../screens/CadastroScreen"; import LoginScreen from "../screens/LoginScreen"; import OnboardingScreen from "../screens/OnboardingScreen"; import TabRoutes from "./tab.routes"; @@ -15,11 +14,12 @@ import { StatusBar, TouchableOpacity, Text } from "react-native"; import { Ionicons } from "@expo/vector-icons"; import ScannerScreen from "../screens/BarcodeScreen"; import ProductDetailsScreen from "../screens/ProductScreen"; -import Dashboard from "../screens/HomeScreen"; import React from "react"; import ProductDetailsScreenPG from "../screens/ProductPG"; import AlimentosConsumidosScreen from "../screens/AlimentosConsumidosScreen"; import SelectRefeicao from "../screens/SelectRefeicao"; +import Main from "../screens/HomeScreen"; +import { IuserLogin } from "../types/user"; const Stack = createStackNavigator(); @@ -27,15 +27,19 @@ export default function StackRoutes() { const [isOnboardingCompleted, setIsOnboardingCompleted] = useState< null | boolean >(null); + const [user,setUser] = useState(); useEffect(() => { const checkOnboardingStatus = async () => { const completed = await AsyncStorage.getItem("onboardingCompleted"); setIsOnboardingCompleted(completed === "true"); + + const userData = await AsyncStorage.getItem("user"); + setUser(userData ? JSON.parse(userData) : null); }; checkOnboardingStatus(); - }, []); + }, [user?.profileCompleted]); if (isOnboardingCompleted === null) { return null; // Exibe um loading ou algo enquanto verifica o AsyncStorage @@ -43,11 +47,11 @@ export default function StackRoutes() { return ( ({ headerShown: !(route.name === "Onboarding"), headerLeft: - route.name === "Login" || route.name === "Cadastro" + route.name === "Main" ? () => ( navigation.goBack()} @@ -67,42 +71,13 @@ export default function StackRoutes() { {!isOnboardingCompleted && ( )} - - - - + + + + diff --git a/frontend/src/routes/tab.routes.tsx b/frontend/src/routes/tab.routes.tsx index 330cd9c..09718e7 100644 --- a/frontend/src/routes/tab.routes.tsx +++ b/frontend/src/routes/tab.routes.tsx @@ -1,23 +1,23 @@ import { createBottomTabNavigator } from "@react-navigation/bottom-tabs"; import { StatusBar } from "react-native"; import Ionicons from "react-native-vector-icons/Ionicons"; -import HomeScreen from "../screens/HomeScreen"; -import AddScreen from "../screens/AddScreen"; import AlimentosConsumidosScreen from "../screens/AlimentosConsumidosScreen"; import ProfileScreen from "../screens/ProfileScreen"; import SelectAlimento from "../screens/SelectAlimento"; import ScannerScreen from "../screens/BarcodeScreen"; +import Main from "../screens/HomeScreen"; const Tab = createBottomTabNavigator(); export default function TabRoutes() { + return ( ({ tabBarIcon: ({ focused, color, size }) => { let iconName: string = ""; - if (route.name === "Home") { + if (route.name === "Dashboard") { iconName = "home"; } else if (route.name === "Search") { iconName = "search"; @@ -42,8 +42,8 @@ export default function TabRoutes() { })} > navigation.goBack() }, // Navigate back to the previous screen diff --git a/frontend/src/screens/CadastroScreen/index.tsx b/frontend/src/screens/CadastroScreen/index.tsx index 7f138b5..7e11464 100644 --- a/frontend/src/screens/CadastroScreen/index.tsx +++ b/frontend/src/screens/CadastroScreen/index.tsx @@ -37,8 +37,7 @@ export default function CadastroScreen({ navigation }: Props) { try { const storedUser = await AsyncStorage.getItem("user") if (storedUser) { - navigation.navigate("Main"); - } + navigation.navigate("Main", { user: JSON.parse(storedUser) }); } } catch (error) { console.error("Erro ao obter dados do AsyncStorage:", error); } @@ -76,20 +75,15 @@ export default function CadastroScreen({ navigation }: Props) { }), }); - const data = await response.json(); + if (response.ok) { - const firstDate = await axios.post(`${BACKEND_API_URL}/data/${data.idUserPostgres}`, - { data: moment().utc().format("YYYY-MM-DD") } - ) - if (firstDate.status == 200) { - Alert.alert("Conta criada com sucesso!"); - - } + Alert.alert("Success", "Cadastro Realizado com suceeso."); + console.log("cadastro com sucesso",response) navigation.navigate("Login"); } - } catch (error) { - console.error("Erro ao cadastrar usuário:", error); + } catch (error:any) { + console.log("Erro ao cadastrar usuário:", error.message); Alert.alert("Erro", "Erro ao cadastrar usuário. Tente novamente."); } }; diff --git a/frontend/src/screens/EditProfile/index.tsx b/frontend/src/screens/EditProfile/index.tsx index 94858e5..445297d 100644 --- a/frontend/src/screens/EditProfile/index.tsx +++ b/frontend/src/screens/EditProfile/index.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useContext, useEffect, useState } from 'react'; import { StatusBar, ScrollView, View, Text, SafeAreaView, TouchableOpacity, Alert } from 'react-native'; import { Menu, Button, Provider } from 'react-native-paper'; import ProfilePicture from '../../components/ProfilePicture'; @@ -12,6 +12,7 @@ import { IuserLogin } from '../../types/user'; import { RootStackParamList } from '../../types'; import { StackNavigationProp } from '@react-navigation/stack'; import { useNavigation } from '@react-navigation/native'; +import { UserContext } from '../../context/userContext'; type EditProfileScreenNavigationProp = StackNavigationProp; @@ -23,19 +24,17 @@ const EditProfile: React.FC = () => { const [userData, setUserData] = useState(); const [nomeUsuario, setNomeUsuario] = useState(''); const [userLogin, setUserLogin] = useState(); - const [altura, setAltura] = useState(''); const [genero, setGenero] = useState(''); // Mantém o estado do gênero const [peso, setPeso] = useState(''); const [meta, setMeta] = useState('Selecione a meta'); const [generoMenuVisible, setGeneroMenuVisible] = useState(false); const [metaMenuVisible, setMetaMenuVisible] = useState(false); + const userContexto = useContext(UserContext); + const userContextoProfile = userContexto?.user + const setUserContexto = userContexto?.setUser + - const openMenu = () => setGeneroMenuVisible(true); - const closeMenu = () => setGeneroMenuVisible(false); - const openMetaMenu = () => setMetaMenuVisible(true); - const closeMetaMenu = () => setMetaMenuVisible(false); - const loadUserFromStorage = async () => { try { @@ -82,12 +81,24 @@ const EditProfile: React.FC = () => { }, [userLogin]); const updateStorage = async () => { - const myUser = { id: userLogin?.id, nomeUsuario: nomeUsuario, email: userLogin?.email } - try { - await AsyncStorage.setItem("user", JSON.stringify(myUser)); - console.log("Dados do usuário atualizados no AsyncStorage:", myUser); - } catch (error) { - console.error("Erro ao atualizar AsyncStorage:", error); + if (userData && userLogin) { + try { + const myUser: IuserLogin = { + nomeUsuario: nomeUsuario, + altura: userData.altura.toString(), peso: userData.peso.toString(), genero: userData.genero, email: userLogin.email, id: userLogin.id, + profileCompleted: true + } + await AsyncStorage.setItem("user", JSON.stringify(myUser)) + console.log("Dados do usuário atualizados no AsyncStorage:", myUser); + setUserLogin(myUser) + if(setUserContexto) + setUserContexto(myUser); + + } + + catch (error) { + console.error("Erro ao atualizar AsyncStorage:", error); + } } } const handleSaveChanges = async () => { @@ -110,16 +121,16 @@ const EditProfile: React.FC = () => { }); const data = await response.json(); - updateStorage() if (response.ok) { - updateStorage(); + await updateStorage(); Alert.alert('Sucesso', data.message); - navigation.navigate('ProfileScreen'); // Salva e volta para ProfileScreen + navigation.goBack(); + // Salva e volta para ProfileScreen } else { Alert.alert('Erro', data.message); } - + } catch (error) { console.log('Erro na função handleSaveChanges:', error); Alert.alert('Erro', 'Não foi possível atualizar o perfil'); @@ -165,7 +176,7 @@ const EditProfile: React.FC = () => { } > - { setGenero('Outros'); setGeneroMenuVisible(false); }} title="Outros" /> + { setGenero('Outros'); setGeneroMenuVisible(false); }} title="Outros" /> { setGenero('Masculino'); setGeneroMenuVisible(false); }} title="Masculino" /> { setGenero('Feminino'); setGeneroMenuVisible(false); }} title="Feminino" /> diff --git a/frontend/src/screens/HomeScreen/index.tsx b/frontend/src/screens/HomeScreen/index.tsx index 0952b44..d798252 100644 --- a/frontend/src/screens/HomeScreen/index.tsx +++ b/frontend/src/screens/HomeScreen/index.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useCallback } from "react"; +import React, { useState, useEffect, useCallback, useContext } from "react"; import axios from "axios"; import moment from "moment"; import { IUser, IUserData } from "../../types/userDiary"; @@ -22,8 +22,9 @@ import { StackNavigationProp } from "@react-navigation/stack"; import { RootStackParamList } from "../../../types"; import AsyncStorage from "@react-native-async-storage/async-storage"; import { IuserLogin } from "../../types/user"; -import { useNavigation } from '@react-navigation/native'; // Importação da navegação +import { useNavigation, useRoute } from '@react-navigation/native'; // Importação da navegação import { Alert } from 'react-native'; +import { UserContext } from "../../context/userContext"; type MainNavigationProp = StackNavigationProp; type ItemData = { id: number; @@ -33,16 +34,17 @@ type ItemData = { type Props = { navigation: MainNavigationProp; }; -const HomeScreen = ({ navigation }: Props) => { +const Main = ({ navigation }: Props) => { const navigationMetrica = useNavigation(); const [selectedId, setSelectedId] = useState(); const [loading, setLoading] = useState(false); const [loadingPast, setLoadingPast] = useState(false); const [dataList, setDataList] = useState([]); - const [userMG, setUserMG] = useState(); - const [user, setUser] = useState(); + const [userMG, setUserMG] = useState() || null; const [userPG, setUserPG] = useState(); - + const userContexto = useContext(UserContext); + const user = userContexto?.user + const setUser = userContexto?.setUser type AguaComponentNavigationProp = StackNavigationProp< RootStackParamList, @@ -55,30 +57,30 @@ const HomeScreen = ({ navigation }: Props) => { "AlimentacaoComponent" >; + + useEffect(() => { - const timer = setTimeout(() => { - if (!userMG || !userPG) return; - - const isProfileIncomplete = - !userPG.nomeUsuario || !userPG.altura || !userPG.peso || !userPG.genero || !userPG.meta; - - if (isProfileIncomplete) { - Alert.alert( - "Cadastro Incompleto", - "Seu cadastro está incompleto. Você será redirecionado para completar o perfil.", - [ - { - text: "OK", - onPress: () => navigation.navigate("EditProfile"), // Redireciona para a tela de edição de perfil - }, - ] - ); - } - }, 2000); // Executa a verificação após 2 segundos - - return () => clearTimeout(timer); - }, [userPG, navigation]); + if (!userContexto) return; + console.log("USEEFFET", user) + const isProfileIncomplete = + !user?.nomeUsuario || !user.altura || !user.peso || !user.genero; + + if (isProfileIncomplete) { + Alert.alert( + "Cadastro Incompleto", + "Seu cadastro está incompleto. Você será redirecionado para completar o perfil.", + [ + { + text: "OK", + onPress: () => navigation.navigate("EditProfile"), // Redireciona para a tela de edição de perfil + }, + ] + ); + } + // Executa a verificação após 2 segundos + + }, [userPG, navigation]); const formatDateTitle = (date: moment.Moment): string => { return `${date.format("ddd")}\n${date.format("DD/MM")}`; @@ -106,20 +108,6 @@ const HomeScreen = ({ navigation }: Props) => { }; - const loadUserFromStorage = async () => { - try { - const storedUser = await AsyncStorage.getItem("user") - if (storedUser) { - setUser(JSON.parse(storedUser)); - await loadDashboard(JSON.parse(storedUser), moment().utc().format("YYYY-MM-DD")).then((response: any) => { - setUserMG(response.userMG); - setUserPG(response.userPG); - }) - } - } catch (error) { - console.log("Erro ao obter dados do AsyncStorage:", error); - } - }; useEffect(() => { navigation.addListener('focus', async () => { const initialData: ItemData[] = []; @@ -132,9 +120,14 @@ const HomeScreen = ({ navigation }: Props) => { }); } setDataList(initialData); - setSelectedId(initialData[2].id); - await loadUserFromStorage() // Load user from AsyncStorage - }) + setSelectedId(initialData[2].id) + + await loadDashboard(user?.id, moment.utc().format("YYYY-MM-DD")) + + + } + ) + }, [navigation]) @@ -155,6 +148,7 @@ const HomeScreen = ({ navigation }: Props) => { } setDataList((prevList) => [...prevList, ...newDates]); + setLoading(false); }; @@ -163,42 +157,41 @@ const HomeScreen = ({ navigation }: Props) => { const response = await axios.post(`${BACKEND_API_URL}/data/${idUser}`, { data: date, }); - const newItem: ItemData = { - date: date, - id: Math.random(), - title: response.data.data, - }; + console.log("nova data gerada", date) setUserMG(response.data.user); + setLoading(false); } catch (error: any) { console.error("ERROR:", error.message); } }; + const setDataStorage = async (date: string) => { + await AsyncStorage.setItem("date", JSON.stringify(date)); + + } const loadDashboard = async (myUser: any, date: string) => { + + try { - const response = await axios.post( - `${BACKEND_API_URL}/dashboard/${myUser.id}`, - { - data: date, - } - ) - await setDataStorage(date); - return response.data + const response = await axios.post(`${BACKEND_API_URL}/dashboard/${myUser}`, { + data: date, + }); + await AsyncStorage.setItem(`dashboard-${myUser}-${date}`, JSON.stringify(response.data)); - } catch (error: any) { + setUserMG(response.data.userMG); + setUserPG(response.data.userPG); + await setDataStorage(date); + } catch (error) { console.log("ERRO ao buscar dados dashboard, criando nova data..."); if (user) { createDate(date, parseInt(user.id)); + setLoading(false); } - setLoading(false); } }; - const setDataStorage = async (date: string) => { - await AsyncStorage.setItem("date", JSON.stringify(date)); - } const handleDatePress = async (item: ItemData) => { setSelectedId(item.id); @@ -207,7 +200,7 @@ const HomeScreen = ({ navigation }: Props) => { if (user) { try { const response = await axios.post( - `${BACKEND_API_URL}/dashboard/${user.id}`, + `${BACKEND_API_URL}/dashboard/${user?.id}`, { data: item.date, } @@ -220,7 +213,7 @@ const HomeScreen = ({ navigation }: Props) => { } catch (error: any) { console.log("ERRO ao buscar dados dashboard, criando nova data..."); if (user) { - createDate(item.date, parseInt(user.id)); + createDate(item.date, parseInt(user?.id)); } } } @@ -234,6 +227,7 @@ const HomeScreen = ({ navigation }: Props) => { const color = item.id === selectedId ? "#fff" : "#ffffff9e"; + return ( handleDatePress(item)} @@ -248,7 +242,7 @@ const HomeScreen = ({ navigation }: Props) => { {!userMG ? - + : @@ -268,7 +262,7 @@ const HomeScreen = ({ navigation }: Props) => { ListHeaderComponent={renderHeader} ListFooterComponent={renderFooter} onScroll={({ nativeEvent }) => { - if (nativeEvent.contentOffset.x <= 10) { + if (nativeEvent.contentOffset.x <= 0.1) { loadPastDates(); } }} @@ -352,4 +346,4 @@ const styles = StyleSheet.create({ } }); -export default HomeScreen; +export default Main; diff --git a/frontend/src/screens/LoginScreen/index.tsx b/frontend/src/screens/LoginScreen/index.tsx index c3331fc..c26a2bf 100644 --- a/frontend/src/screens/LoginScreen/index.tsx +++ b/frontend/src/screens/LoginScreen/index.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useContext, useEffect, useState } from "react"; import { View, Text, @@ -14,6 +14,8 @@ import { StackNavigationProp } from "@react-navigation/stack"; import { RootStackParamList } from "../../../types"; import { BACKEND_API_URL } from "@env"; import Icon from "react-native-vector-icons/FontAwesome"; +import { IuserLogin } from "../../types/user"; +import { UserContext } from "../../context/userContext"; const logo = require("../../../assets/logo.png"); @@ -28,12 +30,17 @@ export default function LoginScreen({ navigation }: Props) { const [password, setPassword] = useState(""); const [loading, setLoading] = useState(false); const [showPassword, setShowPassword] = useState(false); + const ContextUser = useContext(UserContext); + const loadUserFromStorage = async () => { try { const storedUser = await AsyncStorage.getItem("user"); if (storedUser) { - navigation.navigate("Main"); // Navega para HomeScreen se o usuário estiver no AsyncStorage + const user: IuserLogin = JSON.parse(storedUser) + ContextUser?.setUser(user) + + // Navega para HomeScreen se o usuário estiver no AsyncStorage } } catch (error: any) { console.log("Necessário logar"); @@ -54,13 +61,15 @@ export default function LoginScreen({ navigation }: Props) { const { message, user } = response.data; if (message === "Login realizado com sucesso!") { await AsyncStorage.setItem("user", JSON.stringify(user)); - navigation.navigate("Main"); // Navega diretamente para a HomeScreen + ContextUser?.setUser(user); + + } else { Alert.alert("Erro", "Credenciais inválidas."); } - } catch (error) { + } catch (error: any) { Alert.alert("Erro", "Não foi possível realizar o login."); - console.error("Erro de login:", error); + console.error("Erro de login:", error.message); } finally { setLoading(false); } diff --git a/frontend/src/screens/ProfileScreen/index.tsx b/frontend/src/screens/ProfileScreen/index.tsx index 8b27c3c..3fd1280 100644 --- a/frontend/src/screens/ProfileScreen/index.tsx +++ b/frontend/src/screens/ProfileScreen/index.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, useContext } from "react"; import { View, Text, @@ -18,6 +18,7 @@ import { IuserLogin } from "../../types/user"; import AsyncStorage from "@react-native-async-storage/async-storage"; import { BACKEND_API_URL } from "@env"; import axios from "axios"; +import { UserContext } from "../../context/userContext"; type ProfileScreenNavigationProp = StackNavigationProp< RootStackParamList, @@ -39,7 +40,9 @@ export default function ProfileScreen({ navigation }: Props) { const [userLogin, setUserLogin] = useState(); const [userData, setUserData] = useState(); const [nomeUsuario, setNomeUsuario] = useState(""); - + const userContexto = useContext(UserContext); + const userContextoProfile = userContexto?.user + const setUserContexto = userContexto?.setUser useEffect(() => { loadUserFromStorage(); // Carrega os dados do AsyncStorage, inclusive o nome do usuário }, []); @@ -163,11 +166,18 @@ export default function ProfileScreen({ navigation }: Props) { }; const handleLogout = async () => { - console.log("Saindo da conta..."); - setModalVisible(false); // Fechar o modal após a confirmação de logout - await AsyncStorage.clear().then(() => { - navigation.navigate("Login"); - }); + try { + console.log("Saindo da conta..."); + + // Limpar AsyncStorage + await AsyncStorage.clear(); + if (setUserContexto) { + setUserContexto(null) + } + + } catch (error) { + console.error("Erro ao fazer logout:", error); + } }; const handleCancel = () => { @@ -182,7 +192,7 @@ export default function ProfileScreen({ navigation }: Props) { - + >(); @@ -52,7 +52,7 @@ export default function SelectAlimento() { }; initializeData(); }, []); - + useEffect(() => { const fetchData = async () => { if (userId && searchTerm.length === 0) { @@ -63,9 +63,9 @@ export default function SelectAlimento() { } }; fetchData(); - }, [userId,searchTerm]); + }, [userId, searchTerm]); + - // Função para carregar o ID do usuário do AsyncStorage const loadUserFromStorage = async () => { @@ -81,7 +81,7 @@ export default function SelectAlimento() { }; // Função para buscar alimentos cadastrados no backend - const fetchAlimentosCadastrados = async (quantity:number): Promise => { + const fetchAlimentosCadastrados = async (quantity: number): Promise => { setLoading(true) try { const response = await axios.get(`${BACKEND_API_URL}/alimentos/${userId}/${quantity}`); @@ -105,12 +105,12 @@ export default function SelectAlimento() { } }; - const buscarAlimentoCadastrado = async():Promise =>{ - try{ - const response = await axios.get(`${BACKEND_API_URL}/findAlimento/${userId}/${searchTerm}`) + const buscarAlimentoCadastrado = async (): Promise => { + try { + const response = await axios.get(`${BACKEND_API_URL}/searchAlimentoByName/${userId}/${searchTerm}`) return response.data - }catch(error:any){ - console.log("Não encontrou no banco",error.message) + } catch (error: any) { + console.log("Não encontrou no banco", error.message) return [] } } @@ -146,12 +146,12 @@ export default function SelectAlimento() { const fetchAndCombineAlimentos = async () => { try { setLoading(true); - + const databaseProducts = await buscarAlimentoCadastrado(); const externalProducts = await searchExternalProducts(); setAlimentos([]) - const combineProducts = [...databaseProducts,...externalProducts] - + const combineProducts = [...databaseProducts, ...externalProducts] + setAlimentos(combineProducts); } catch (error) { console.error("Error fetching alimentos:", error); @@ -160,8 +160,8 @@ export default function SelectAlimento() { setLoading(false); } }; - - + + // Lógica de alternância de favoritos const toggleFavorite = async (food: IAlimentos) => { @@ -196,31 +196,27 @@ export default function SelectAlimento() { ? alimentos.filter((product) => product.isFavorito) : alimentos; - const loadMoreAlimentos = async () => { - if (!loadingMore) { - if(quantity > 100 && alimentos.length > 45){ - return false; - } - setLoading(true) - setLoadingMore(true); - const newQuantity = quantity + 10; - setQuantity(newQuantity); - - // Chamar `fetchAlimentosCadastrados` com o valor atualizado de `newQuantity` - const moreAlimentos = await fetchAlimentosCadastrados(newQuantity); - - // Atualizar a lista de alimentos com o novo conjunto carregado - setAlimentos(moreAlimentos); - setLoadingMore(false); - setLoading(false) + const loadMoreAlimentos = async () => { + if (!loadingMore) { + if (quantity > 100 && alimentos.length > 45) { + return false; } - - }; - - - useEffect(() => { - console.log("Filtered Alimentos:", filteredAlimentos); - }, [filteredAlimentos]); + setLoading(true) + setLoadingMore(true); + const newQuantity = quantity + 10; + setQuantity(newQuantity); + + // Chamar `fetchAlimentosCadastrados` com o valor atualizado de `newQuantity` + const moreAlimentos = await fetchAlimentosCadastrados(newQuantity); + + // Atualizar a lista de alimentos com o novo conjunto carregado + setAlimentos(moreAlimentos); + setLoadingMore(false); + setLoading(false) + } + + }; + return ( @@ -296,11 +292,11 @@ export default function SelectAlimento() { keyExtractor={(key) => Math.random().toString()} onEndReached={loadMoreAlimentos} onEndReachedThreshold={0.01} - ListFooterComponent={loadingMore ? Loading more... : null} + /> - {loading && - -} + {loading && + + } ); } \ No newline at end of file diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index deb8307..7e04d4d 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -1,4 +1,5 @@ import { ParamListBase } from "@react-navigation/native"; +import { IuserLogin } from "./user"; export interface RootStackParamList extends ParamListBase { Home: undefined; // A tela Home não espera parâmetros @@ -8,7 +9,7 @@ export interface RootStackParamList extends ParamListBase { Settings: undefined; Login: undefined; Cadastro: undefined; - Main: undefined; + Main: {user:IuserLogin}; Onboarding: undefined; Agua: undefined; Alimentacao: undefined; diff --git a/frontend/src/types/user.ts b/frontend/src/types/user.ts index 0292832..73a6fab 100644 --- a/frontend/src/types/user.ts +++ b/frontend/src/types/user.ts @@ -3,4 +3,7 @@ export interface IuserLogin{ id:string; nomeUsuario:string; email:string; + altura:string; + peso:string; + genero:string; } \ No newline at end of file diff --git a/frontend/types/index.ts b/frontend/types/index.ts index 303d1d5..49169e9 100644 --- a/frontend/types/index.ts +++ b/frontend/types/index.ts @@ -1,14 +1,13 @@ import { ParamListBase } from "@react-navigation/native"; - +import { IuserLogin } from "../src/types/user"; export interface RootStackParamList extends ParamListBase { - Home: undefined; // A tela Home não espera parâmetros Profile: undefined; EditProfile: undefined; termsOfUse: undefined; Settings: undefined; Login: undefined; Cadastro: undefined; - Main: undefined; + Main: {user:IuserLogin}; Onboarding: undefined; Agua: undefined; Alimentacao: undefined;