Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

corrigindo favoritos #49

Merged
merged 1 commit into from
Oct 25, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions backend/src/routes/alimento.ts
Original file line number Diff line number Diff line change
@@ -6,14 +6,11 @@ import AlimentoController from "../controllers/alimentosController";
const FoodRouter = Router();

FoodRouter.post("/alimentos", AlimentoController.createAlimento);
FoodRouter.get("/alimentos",AlimentoController.buscarAlimentos);
FoodRouter.get("/findAlimento/:barcode",AlimentoController.findAlimento);
FoodRouter.post("/addAlimento/",AlimentoController.addAlimento);
FoodRouter.post("/consumidos",AlimentoController.alimentosConsumidos);
FoodRouter.post("/favoritos/:id",AlimentoController.favoritosAlimentos);
FoodRouter.post("/addFavorito",AlimentoController.adicionarRemoverFavorito);



FoodRouter.get("/alimentos", AlimentoController.buscarAlimentos);
FoodRouter.get("/findAlimento/:barcode", AlimentoController.findAlimento);
FoodRouter.post("/addAlimento/", AlimentoController.addAlimento);
FoodRouter.post("/consumidos", AlimentoController.alimentosConsumidos);
FoodRouter.get("/favoritos/:id", AlimentoController.favoritosAlimentos);
FoodRouter.post("/addFavorito", AlimentoController.adicionarRemoverFavorito);

export default FoodRouter;
59 changes: 29 additions & 30 deletions frontend/src/screens/ProductPG/index.tsx
Original file line number Diff line number Diff line change
@@ -7,42 +7,42 @@ import Ionicons from "react-native-vector-icons/Ionicons";
import { IAlimentos } from "../../types/AlimentosPG";
import { IuserLogin } from "../../types/user";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { StackNavigationProp } from '@react-navigation/stack';
import { StackNavigationProp } from "@react-navigation/stack";
import { RootStackParamList } from "../../types";
type ProductScreenNavigationProp = StackNavigationProp<RootStackParamList, "Profile">;
type ProductScreenNavigationProp = StackNavigationProp<
RootStackParamList,
"Profile"
>;

export default function ProductDetailsScreenPG() {
const route = useRoute();
const { barcode, meal } = route.params as { barcode: string, meal: string };
const { barcode, meal } = route.params as { barcode: string; meal: string };
const [product, setProduct] = useState<IAlimentos | null>(null);
const [quantity, setQuantity] = useState(1);
const [weight, setWeight] = useState(100);
const [user, setUser] = useState<IuserLogin>();
const [myDate, setData] = useState("");
const navigation = useNavigation<ProductScreenNavigationProp>();


const loadUserFromStorage = async () => {
try {
const storedUser = await AsyncStorage.getItem("user")
const dataSelected = await AsyncStorage.getItem("date")
const storedUser = await AsyncStorage.getItem("user");
const dataSelected = await AsyncStorage.getItem("date");

if (storedUser) {
setUser(JSON.parse(storedUser));
console.log("Usuário do AsyncStorage:", storedUser);
}

if (dataSelected) {
setData(dataSelected)
setData(dataSelected);
console.log("DATA RECEBIDA PELO STORAGE", dataSelected);
}

} catch (error) {
console.error("Erro ao obter dados do AsyncStorage:", error);
}
};


const handleIncreaseQuantity = () => setQuantity((prev) => prev + 1);
const handleDecreaseQuantity = () =>
setQuantity((prev) => (prev > 1 ? prev - 1 : 1));
@@ -89,6 +89,8 @@ export default function ProductDetailsScreenPG() {
gordura: productData.nutriments.fat_100g?.toString() || "0",
sodio: productData.nutriments.sodium_100g?.toString() || "0",
acucar: productData.nutriments.sugars_100g?.toString() || "0",
tiporefeicao: meal,
quantidade: quantity.toString(),
});
} else {
Alert.alert("Erro", "Produto não encontrado.");
@@ -101,7 +103,7 @@ export default function ProductDetailsScreenPG() {

useEffect(() => {
if (barcode) {
loadUserFromStorage()
loadUserFromStorage();
fetchProductFromBackend();
}
}, [barcode]);
@@ -115,14 +117,14 @@ export default function ProductDetailsScreenPG() {
const data = formatResponse();

const response = await axios.post(`${BACKEND_API_URL}/addAlimento`, {
data
})
data,
});

if (response.status === 201) {
Alert.alert("Tudo certo!", "Alimento adicionado a dieta do dia.")
navigation.navigate("SelectAlimento")
Alert.alert("Tudo certo!", "Alimento adicionado a dieta do dia.");
navigation.navigate("SelectAlimento");
}
}
};

const formatResponse = () => {
if (product) {
@@ -140,35 +142,32 @@ export default function ProductDetailsScreenPG() {
idUser: user?.id,
date: myDate,
meal: meal,
quantidade: quantity
}
return data

quantidade: quantity,
};
return data;
}
const data = {}
return data
}
const data = {};
return data;
};

const handleRegister = async () => {
if (!product) return;

try {

const findAlimento = await axios.get(`${BACKEND_API_URL}/findAlimento/${product.barcode}`) // VERIFICA SE O ALIMENTO JÁ EXISTE NO BANCO
const findAlimento = await axios.get(
`${BACKEND_API_URL}/findAlimento/${product.barcode}`
); // VERIFICA SE O ALIMENTO JÁ EXISTE NO BANCO

if (findAlimento.status !== 201) {

try {
const data = formatResponse();
const response = await axios.post(`${BACKEND_API_URL}/alimentos`, {
data
data,
});

addAlimentoToUserDiary();
return;

}
catch (error) {
} catch (error) {
console.error("Erro ao registrar o produto:", error);
Alert.alert("Erro", "Falha ao registrar o produto.");
}
@@ -345,4 +344,4 @@ const styles = StyleSheet.create({
fontSize: 16,
fontWeight: "bold",
},
});
});
150 changes: 86 additions & 64 deletions frontend/src/screens/SelectAlimento/index.tsx
Original file line number Diff line number Diff line change
@@ -16,37 +16,62 @@ import { BACKEND_API_URL } from "@env";
import { IAlimentos } from "../../types/AlimentosPG";
import AsyncStorage from "@react-native-async-storage/async-storage";

// Interface para os produtos externos (API OpenFoodFacts)
interface ExternalProduct {
idProduto: string | null;
code: number;
product_name: string;
image_url: string | null;
nutriments: {
proteins: number;
energy: number;
carbohydrates: number;
fat: number;
sodium: number;
sugars: number;
};
}

export default function SelectAlimento() {
const [searchTerm, setSearchTerm] = useState("");
const [showFavorites, setShowFavorites] = useState(false);
const [favoritos, setFavoritos] = useState<IAlimentos[]>([]);
const [alimentos, setAlimentos] = useState<IAlimentos[]>([]);
const [userId, setUserId] = useState<string | null>(null);

const [isSearching, setIsSearching] = useState(false);
const [page, setPage] = useState(1);
const navigation = useNavigation<NavigationProp<RootStackParamList>>();

useEffect(() => {
fetchAlimentosCadastrados();
loadUserFromStorage();
}, []);

useEffect(() => {
if (searchTerm.length === 0) {
fetchAndCombineAlimentos();
}
}, [searchTerm]);

// Função para carregar o ID do usuário do AsyncStorage
const loadUserFromStorage = async () => {
try {
const storedUser = await AsyncStorage.getItem("user");
if (storedUser) {
const id = JSON.parse(storedUser).id;
setUserId(id); // Armazena o ID do usuário no estado
await fetchFavoritos(id); // Passa o ID para buscar os favoritos
setUserId(id);
await fetchFavoritos(id);
}
} catch (error) {
console.log("Erro ao obter dados do AsyncStorage:", error);
}
};


// Função para buscar todos os alimentos cadastrados
const fetchAlimentosCadastrados = async () => {
// Função para buscar alimentos cadastrados no backend
const fetchAlimentosCadastrados = async (): Promise<IAlimentos[]> => {
try {
const response = await axios.get(`${BACKEND_API_URL}/alimentos`);
const alimentosFormatados = response.data.map((item: IAlimentos) => ({
return response.data.map((item: IAlimentos) => ({
Caloria: parseFloat(item.Caloria),
Carboidrato: parseFloat(item.Carboidrato),
Proteina: parseFloat(item.Proteina),
@@ -58,101 +83,103 @@ export default function SelectAlimento() {
nomeProduto: item.nomeProduto,
sodio: parseFloat(item.sodio),
}));
setAlimentos(alimentosFormatados);
} catch (error) {
console.error("Erro ao buscar alimentos cadastrados:", error);
Alert.alert("Erro", "Não foi possível buscar os alimentos.");
return [];
}
};

// Função para buscar produtos da API OpenFoodFacts
const searchExternalProducts = async (): Promise<IAlimentos[]> => {
try {
const response = await axios.get(
`https://br.openfoodfacts.org/cgi/search.pl?search_terms=${searchTerm}&search_simple=1&action=process&json=1&page=${page}`
);

// Carregar alimentos cadastrados na montagem do componente
useEffect(() => {
fetchAlimentosCadastrados();
loadUserFromStorage();
}, []);
return response.data.products.map((product: ExternalProduct) => ({
Caloria: product.nutriments.energy,
Carboidrato: product.nutriments.carbohydrates,
Proteina: product.nutriments.proteins,
acucar: product.nutriments.sugars,
barcode: product.code.toString(),
gordura: product.nutriments.fat,
idProduto: 0, // Valor fictício, pois a API externa não fornece esse dado
imageSrc: product.image_url,
nomeProduto: product.product_name,
sodio: product.nutriments.sodium,
}));
} catch (error) {
console.error("Erro ao buscar produtos externos:", error);
Alert.alert("Erro", "Não foi possível buscar os produtos.");
return [];
}
};

// Função para combinar alimentos do backend e da API externa
const fetchAndCombineAlimentos = async () => {
const alimentosCadastrados = await fetchAlimentosCadastrados();
const externalProducts = await searchExternalProducts();
setAlimentos([...alimentosCadastrados, ...externalProducts]);
};

// Função para buscar alimentos favoritos do backend
// Função para buscar favoritos do usuário
const fetchFavoritos = async (id: string) => {
try {
const response = await axios.get(`${BACKEND_API_URL}/favoritos/${id}`);

if (response.status === 200 && response.data.length > 0) {
// Se a resposta for 200 e houver favoritos, define os favoritos
setFavoritos(response.data);
console.log("Favoritos:", response.data);
} else if (response.status === 200 && response.data.length === 0) {
// Se a resposta for 200, mas não houver favoritos
} else {
console.log("Nenhum alimento favorito encontrado.");
}
} catch (error: any) {
if (error.response && error.response.status === 404) {
// Se o erro for 404, loga a mensagem sem alertar o usuário
console.log("Nenhum alimento favorito encontrado.");
} else {
// Para outros tipos de erro, mostra o alert
console.error("Erro ao buscar favoritos:", error);
Alert.alert("Erro", "Não foi possível carregar seus favoritos.");
}
}
};



// Exibir favoritos ao clicar no botão "Meus Favoritos"
const handleShowFavorites = async () => {
setShowFavorites(true);
//await fetchFavoritos();
};


// Lógica de alternância de favoritos
const toggleFavorite = async (food: IAlimentos) => {
const isFavorite = favoritos.some((fav) => fav.idProduto === food.idProduto);
const isFavorite = favoritos.some(
(fav) => fav.idProduto === food.idProduto
);
const updatedFavorites = isFavorite
? favoritos.filter((fav) => fav.idProduto !== food.idProduto)
: [...favoritos, food];

setFavoritos(updatedFavorites); // Atualiza os favoritos localmente
? favoritos.filter((fav) => fav.idProduto !== food.idProduto)
: [...favoritos, food];

setFavoritos(updatedFavorites);

// Atualiza os favoritos no backend
if (userId) {
try {
await axios.post(`${BACKEND_API_URL}/addFavorito`, {
idProduto: food.idProduto,
idUsuario: userId, // Usa o ID do estado
isFavorito: !isFavorite, // Indica se está favoritando ou desfavoritando
idUsuario: userId,
isFavorito: !isFavorite,
});
} catch (error) {
console.error("Erro ao adicionar favorito:", error);
Alert.alert("Erro", "Não foi possível atualizar seus favoritos.");
}
}
};

// Função para navegar ao selecionar um alimento
const handleSelect = (product: IAlimentos) => {
navigation.navigate("SelectRefeicao", { barcode: product.barcode });
};

// Filtrar alimentos com base na exibição (favoritos ou todos)
const filteredAlimentos = showFavorites
? alimentos.filter((product) =>
favoritos.some((fav) => fav.nomeProduto === product.nomeProduto)
)
favoritos.some((fav) => fav.nomeProduto === product.nomeProduto)
)
: alimentos;


// Função para navegar para outra tela ao selecionar um alimento
const handleSelect = (product: IAlimentos) => {
if (navigation) {
navigation.navigate("SelectRefeicao", { barcode: product.barcode });
}
};


return (
<View style={styles.container}>
<View style={styles.searchContainer}>
<TouchableOpacity onPress={fetchAlimentosCadastrados}>
<TouchableOpacity onPress={fetchAndCombineAlimentos}>
<Ionicons name="search" size={24} color="#777" />
</TouchableOpacity>
<TextInput
@@ -189,7 +216,7 @@ export default function SelectAlimento() {
showFavorites ? styles.activeButton : styles.inactiveButton,
{ borderTopRightRadius: 16, borderBottomRightRadius: 16 },
]}
onPress={handleShowFavorites}
onPress={() => setShowFavorites(true)}
>
<Text
style={
@@ -211,29 +238,24 @@ export default function SelectAlimento() {
onPress={() => handleSelect(product)}
>
<Text style={styles.itemText}>{product.nomeProduto}</Text>
<TouchableOpacity
onPress={() => toggleFavorite(product)} // Passa o objeto `product` completo
>
<TouchableOpacity onPress={() => toggleFavorite(product)}>
<Ionicons
name={
favoritos.some((fav) => fav.idProduto === product.idProduto)
? "heart" // Ícone de coração preenchido para favoritos
: "heart-outline" // Ícone de coração contornado para não favoritos
? "heart"
: "heart-outline"
}
size={24}
color={
favoritos.some((fav) => fav.idProduto === product.idProduto)
? "#FF9385" // Cor para itens favoritos
: "#FFF8EE" // Cor para itens não favoritos
? "#FF9385"
: "#FFF8EE"
}
/>
</TouchableOpacity>
</TouchableOpacity>
))}

</ScrollView>

</View>
);
}
//18-10-2024